@transferwise/components 0.0.0-experimental-4d1e1cf → 0.0.0-experimental-a53ae95
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/README.md +14 -1
- package/build/index.esm.js +147 -49
- package/build/index.esm.js.map +1 -1
- package/build/index.js +147 -49
- package/build/index.js.map +1 -1
- package/build/mocks.esm.js +40 -0
- package/build/mocks.esm.js.map +1 -0
- package/build/mocks.js +43 -0
- package/build/mocks.js.map +1 -0
- package/build/types/index.d.ts +0 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/mocks.d.ts +9 -0
- package/build/types/mocks.d.ts.map +1 -0
- package/build/types/test-utils/window-mock.d.ts.map +1 -1
- package/build/types/typeahead/Typeahead.d.ts +57 -98
- package/build/types/typeahead/Typeahead.d.ts.map +1 -1
- package/build/types/typeahead/index.d.ts +2 -2
- package/build/types/typeahead/index.d.ts.map +1 -1
- package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts +41 -23
- package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts.map +1 -1
- package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts +17 -9
- package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts.map +1 -1
- package/build/types/typeahead/util/highlight.d.ts +1 -2
- package/build/types/typeahead/util/highlight.d.ts.map +1 -1
- package/package.json +23 -10
- package/src/dimmer/Dimmer.spec.js +0 -4
- package/src/index.ts +0 -1
- package/src/mocks.ts +48 -0
- package/src/snackbar/Snackbar.spec.js +0 -4
- package/src/test-utils/window-mock.ts +7 -23
- package/src/typeahead/{Typeahead.tsx → Typeahead.js} +108 -107
- package/src/typeahead/{Typeahead.story.tsx → Typeahead.story.js} +7 -8
- package/src/typeahead/index.js +3 -0
- package/src/typeahead/typeaheadInput/{TypeaheadInput.tsx → TypeaheadInput.js} +51 -43
- package/src/typeahead/typeaheadOption/{TypeaheadOption.tsx → TypeaheadOption.js} +20 -10
- package/src/typeahead/util/{highlight.tsx → highlight.js} +1 -1
- package/src/withNextPortal/withNextPortal.spec.js +0 -4
- package/src/typeahead/index.ts +0 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[](https://github.com/transferwise/neptune-web/actions) [](https://www.npmjs.com/package/@transferwise/components)
|
|
2
2
|
|
|
3
|
-
# Neptune Web React Components
|
|
3
|
+
# Neptune Web React Components
|
|
4
4
|
|
|
5
5
|
Neptune is the Design System built by and used at TransferWise. Neptune Web is the Neptune framework for Web. Neptune Web provides a way to build high quality, consistent user experiences on the web with ease.
|
|
6
6
|
|
|
@@ -48,6 +48,19 @@ Note: types for some of components are not 100% accurate (some of them will be j
|
|
|
48
48
|
|
|
49
49
|
Please follow [rules for JS components](https://github.com/transferwise/neptune-web/blob/main/packages/components/CONTRIBUTING.md#js-component-rules) in order to generate accurate types for them.
|
|
50
50
|
|
|
51
|
+
### Mocks for testing
|
|
52
|
+
|
|
53
|
+
We expose reusable mocks for Jest and Vitest under an isolated entry point. They can be applied by passing the testing framework as the parameter:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { mockMatchMedia, mockResizeObserver } from '@transferwise/components/mocks';
|
|
57
|
+
import { jest } from '@jest/globals';
|
|
58
|
+
import { vi } from 'vitest';
|
|
59
|
+
|
|
60
|
+
mockMatchMedia(jest); // With Jest
|
|
61
|
+
mockResizeObserver(vi); // With Vitest
|
|
62
|
+
```
|
|
63
|
+
|
|
51
64
|
## Documentation
|
|
52
65
|
|
|
53
66
|
Visit the [docs](https://transferwise.github.io/neptune-web/about/Home) for information on getting started, usage information and examples for each component.
|
package/build/index.esm.js
CHANGED
|
@@ -12210,10 +12210,8 @@ const TextareaWithDisplayFormat = props => /*#__PURE__*/jsx(WithDisplayFormat, {
|
|
|
12210
12210
|
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
|
12211
12211
|
const DEFAULT_INPUT_MIN_WIDTH = 10;
|
|
12212
12212
|
class TypeaheadInput extends Component {
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
constructor(props) {
|
|
12216
|
-
super(props);
|
|
12213
|
+
constructor() {
|
|
12214
|
+
super();
|
|
12217
12215
|
this.state = {
|
|
12218
12216
|
inputWidth: DEFAULT_INPUT_MIN_WIDTH
|
|
12219
12217
|
};
|
|
@@ -12223,7 +12221,7 @@ class TypeaheadInput extends Component {
|
|
|
12223
12221
|
autoFocus
|
|
12224
12222
|
} = this.props;
|
|
12225
12223
|
if (autoFocus) {
|
|
12226
|
-
this.inputRef.
|
|
12224
|
+
this.inputRef.focus();
|
|
12227
12225
|
}
|
|
12228
12226
|
}
|
|
12229
12227
|
componentDidUpdate(previousProps) {
|
|
@@ -12234,19 +12232,19 @@ class TypeaheadInput extends Component {
|
|
|
12234
12232
|
recalculateWidth = () => {
|
|
12235
12233
|
requestAnimationFrame(() => {
|
|
12236
12234
|
this.setState({
|
|
12237
|
-
inputWidth: Math.max(DEFAULT_INPUT_MIN_WIDTH, this.sizerRef.
|
|
12235
|
+
inputWidth: Math.max(DEFAULT_INPUT_MIN_WIDTH, this.sizerRef.scrollWidth + 10)
|
|
12238
12236
|
});
|
|
12239
12237
|
});
|
|
12240
12238
|
};
|
|
12241
12239
|
renderInput = () => {
|
|
12242
12240
|
const {
|
|
12243
12241
|
typeaheadId,
|
|
12244
|
-
autoFocus
|
|
12242
|
+
autoFocus,
|
|
12245
12243
|
multiple,
|
|
12246
12244
|
name,
|
|
12247
|
-
optionsShown
|
|
12248
|
-
placeholder
|
|
12249
|
-
selected
|
|
12245
|
+
optionsShown,
|
|
12246
|
+
placeholder,
|
|
12247
|
+
selected,
|
|
12250
12248
|
value,
|
|
12251
12249
|
onChange,
|
|
12252
12250
|
onKeyDown,
|
|
@@ -12259,7 +12257,9 @@ class TypeaheadInput extends Component {
|
|
|
12259
12257
|
} = this.state;
|
|
12260
12258
|
const hasPlaceholder = !multiple || selected.length === 0;
|
|
12261
12259
|
return /*#__PURE__*/jsx(Input, {
|
|
12262
|
-
ref:
|
|
12260
|
+
ref: reference => {
|
|
12261
|
+
this.inputRef = reference;
|
|
12262
|
+
},
|
|
12263
12263
|
className: classNames(multiple && 'typeahead__input'),
|
|
12264
12264
|
name: name,
|
|
12265
12265
|
id: `input-${typeaheadId}`,
|
|
@@ -12285,18 +12285,18 @@ class TypeaheadInput extends Component {
|
|
|
12285
12285
|
render() {
|
|
12286
12286
|
const {
|
|
12287
12287
|
multiple,
|
|
12288
|
-
selected
|
|
12288
|
+
selected,
|
|
12289
12289
|
value,
|
|
12290
|
-
maxHeight
|
|
12290
|
+
maxHeight,
|
|
12291
12291
|
renderChip
|
|
12292
12292
|
} = this.props;
|
|
12293
12293
|
return multiple ? /*#__PURE__*/jsxs("div", {
|
|
12294
12294
|
className: "form-control typeahead__input-container",
|
|
12295
|
-
style: {
|
|
12296
|
-
maxHeight
|
|
12295
|
+
style: maxHeight && {
|
|
12296
|
+
maxHeight
|
|
12297
12297
|
},
|
|
12298
12298
|
onClick: () => {
|
|
12299
|
-
this.inputRef.
|
|
12299
|
+
this.inputRef.focus();
|
|
12300
12300
|
},
|
|
12301
12301
|
children: [/*#__PURE__*/jsxs("div", {
|
|
12302
12302
|
className: "typeahead__input-wrapper",
|
|
@@ -12304,13 +12304,39 @@ class TypeaheadInput extends Component {
|
|
|
12304
12304
|
className: "typeahead__input-aligner"
|
|
12305
12305
|
})]
|
|
12306
12306
|
}), /*#__PURE__*/jsx("div", {
|
|
12307
|
-
ref:
|
|
12307
|
+
ref: reference => {
|
|
12308
|
+
this.sizerRef = reference;
|
|
12309
|
+
},
|
|
12308
12310
|
className: "sizer form-control typeahead__input",
|
|
12309
12311
|
children: value
|
|
12310
12312
|
})]
|
|
12311
12313
|
}) : this.renderInput();
|
|
12312
12314
|
}
|
|
12313
12315
|
}
|
|
12316
|
+
TypeaheadInput.propTypes = {
|
|
12317
|
+
typeaheadId: PropTypes.string.isRequired,
|
|
12318
|
+
name: PropTypes.string.isRequired,
|
|
12319
|
+
autoFocus: PropTypes.bool,
|
|
12320
|
+
multiple: PropTypes.bool.isRequired,
|
|
12321
|
+
value: PropTypes.string.isRequired,
|
|
12322
|
+
selected: PropTypes.arrayOf(PropTypes.object),
|
|
12323
|
+
placeholder: PropTypes.string,
|
|
12324
|
+
optionsShown: PropTypes.bool,
|
|
12325
|
+
maxHeight: PropTypes.number,
|
|
12326
|
+
autoComplete: PropTypes.string.isRequired,
|
|
12327
|
+
onChange: PropTypes.func.isRequired,
|
|
12328
|
+
renderChip: PropTypes.func.isRequired,
|
|
12329
|
+
onKeyDown: PropTypes.func.isRequired,
|
|
12330
|
+
onFocus: PropTypes.func.isRequired,
|
|
12331
|
+
onPaste: PropTypes.func.isRequired
|
|
12332
|
+
};
|
|
12333
|
+
TypeaheadInput.defaultProps = {
|
|
12334
|
+
autoFocus: false,
|
|
12335
|
+
maxHeight: null,
|
|
12336
|
+
placeholder: '',
|
|
12337
|
+
optionsShown: false,
|
|
12338
|
+
selected: []
|
|
12339
|
+
};
|
|
12314
12340
|
|
|
12315
12341
|
function highlight(value, query) {
|
|
12316
12342
|
if (value && query) {
|
|
@@ -12331,9 +12357,9 @@ function highlight(value, query) {
|
|
|
12331
12357
|
const Option = props => {
|
|
12332
12358
|
const {
|
|
12333
12359
|
option,
|
|
12334
|
-
selected
|
|
12335
|
-
onClick
|
|
12336
|
-
query
|
|
12360
|
+
selected,
|
|
12361
|
+
onClick,
|
|
12362
|
+
query
|
|
12337
12363
|
} = props;
|
|
12338
12364
|
const {
|
|
12339
12365
|
label,
|
|
@@ -12363,32 +12389,30 @@ const Option = props => {
|
|
|
12363
12389
|
})
|
|
12364
12390
|
});
|
|
12365
12391
|
};
|
|
12392
|
+
Option.propTypes = {
|
|
12393
|
+
option: PropTypes.shape({
|
|
12394
|
+
label: PropTypes.string.isRequired,
|
|
12395
|
+
note: PropTypes.string,
|
|
12396
|
+
secondary: PropTypes.string
|
|
12397
|
+
}).isRequired,
|
|
12398
|
+
query: PropTypes.string,
|
|
12399
|
+
selected: PropTypes.bool,
|
|
12400
|
+
onClick: PropTypes.func
|
|
12401
|
+
};
|
|
12402
|
+
Option.defaultProps = {
|
|
12403
|
+
selected: false,
|
|
12404
|
+
query: '',
|
|
12405
|
+
onClick: () => {}
|
|
12406
|
+
};
|
|
12407
|
+
var TypeaheadOption = Option;
|
|
12366
12408
|
|
|
12367
12409
|
/* eslint-disable jsx-a11y/anchor-is-valid */
|
|
12368
12410
|
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
|
12369
12411
|
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
|
12412
|
+
|
|
12370
12413
|
const DEFAULT_MIN_QUERY_LENGTH = 3;
|
|
12371
12414
|
const SEARCH_DELAY = 200;
|
|
12372
12415
|
class Typeahead extends Component {
|
|
12373
|
-
static defaultProps = {
|
|
12374
|
-
addon: null,
|
|
12375
|
-
allowNew: false,
|
|
12376
|
-
autoFillOnBlur: true,
|
|
12377
|
-
autoFocus: false,
|
|
12378
|
-
chipSeparators: [],
|
|
12379
|
-
clearable: true,
|
|
12380
|
-
footer: null,
|
|
12381
|
-
initialValue: [],
|
|
12382
|
-
inputAutoComplete: 'new-password',
|
|
12383
|
-
maxHeight: null,
|
|
12384
|
-
minQueryLength: DEFAULT_MIN_QUERY_LENGTH,
|
|
12385
|
-
multiple: false,
|
|
12386
|
-
searchDelay: SEARCH_DELAY,
|
|
12387
|
-
showSuggestions: true,
|
|
12388
|
-
showNewEntry: true,
|
|
12389
|
-
size: Size.MEDIUM,
|
|
12390
|
-
validateChip: () => true
|
|
12391
|
-
};
|
|
12392
12416
|
constructor(props) {
|
|
12393
12417
|
super(props);
|
|
12394
12418
|
const {
|
|
@@ -12405,7 +12429,6 @@ class Typeahead extends Component {
|
|
|
12405
12429
|
keyboardFocusedOptionIndex: null
|
|
12406
12430
|
};
|
|
12407
12431
|
}
|
|
12408
|
-
handleSearchDebounced;
|
|
12409
12432
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
12410
12433
|
if (nextProps.multiple !== this.props.multiple) {
|
|
12411
12434
|
this.setState(previousState => {
|
|
@@ -12419,8 +12442,7 @@ class Typeahead extends Component {
|
|
|
12419
12442
|
};
|
|
12420
12443
|
}
|
|
12421
12444
|
return {
|
|
12422
|
-
query: ''
|
|
12423
|
-
selected: previousState.selected
|
|
12445
|
+
query: ''
|
|
12424
12446
|
};
|
|
12425
12447
|
});
|
|
12426
12448
|
}
|
|
@@ -12429,8 +12451,13 @@ class Typeahead extends Component {
|
|
|
12429
12451
|
this.handleSearchDebounced.cancel();
|
|
12430
12452
|
}
|
|
12431
12453
|
handleOnFocus = () => {
|
|
12454
|
+
const {
|
|
12455
|
+
onFocus
|
|
12456
|
+
} = this.props;
|
|
12432
12457
|
this.showMenu();
|
|
12433
|
-
|
|
12458
|
+
if (onFocus) {
|
|
12459
|
+
this.props.onFocus();
|
|
12460
|
+
}
|
|
12434
12461
|
};
|
|
12435
12462
|
onOptionSelected = (event, item) => {
|
|
12436
12463
|
event.preventDefault();
|
|
@@ -12513,7 +12540,7 @@ class Typeahead extends Component {
|
|
|
12513
12540
|
break;
|
|
12514
12541
|
case 'Enter':
|
|
12515
12542
|
event.preventDefault();
|
|
12516
|
-
if (
|
|
12543
|
+
if (options[keyboardFocusedOptionIndex]) {
|
|
12517
12544
|
this.selectItem(options[keyboardFocusedOptionIndex]);
|
|
12518
12545
|
} else if (allowNew && query.trim()) {
|
|
12519
12546
|
this.selectItem({
|
|
@@ -12565,6 +12592,13 @@ class Typeahead extends Component {
|
|
|
12565
12592
|
query
|
|
12566
12593
|
});
|
|
12567
12594
|
};
|
|
12595
|
+
stopPropagation = event => {
|
|
12596
|
+
event.stopPropagation();
|
|
12597
|
+
event.preventDefault();
|
|
12598
|
+
if (event.nativeEvent && event.nativeEvent.stopImmediatePropagation) {
|
|
12599
|
+
event.nativeEvent.stopImmediatePropagation();
|
|
12600
|
+
}
|
|
12601
|
+
};
|
|
12568
12602
|
handleSearch = query => {
|
|
12569
12603
|
const {
|
|
12570
12604
|
onSearch
|
|
@@ -12649,7 +12683,7 @@ class Typeahead extends Component {
|
|
|
12649
12683
|
}
|
|
12650
12684
|
};
|
|
12651
12685
|
renderChip = (option, idx) => {
|
|
12652
|
-
const valid = this.props.validateChip
|
|
12686
|
+
const valid = this.props.validateChip(option);
|
|
12653
12687
|
return /*#__PURE__*/jsx(Chip, {
|
|
12654
12688
|
label: option.label,
|
|
12655
12689
|
className: classNames('m-t-1', {
|
|
@@ -12684,7 +12718,7 @@ class Typeahead extends Component {
|
|
|
12684
12718
|
className: "dropdown-menu",
|
|
12685
12719
|
role: "menu",
|
|
12686
12720
|
"aria-labelledby": "dropdownMenu1",
|
|
12687
|
-
children: [optionsToRender.map((option, idx) => /*#__PURE__*/jsx(
|
|
12721
|
+
children: [optionsToRender.map((option, idx) => /*#__PURE__*/jsx(TypeaheadOption, {
|
|
12688
12722
|
query: query,
|
|
12689
12723
|
option: option,
|
|
12690
12724
|
selected: keyboardFocusedOptionIndex === idx,
|
|
@@ -12727,7 +12761,6 @@ class Typeahead extends Component {
|
|
|
12727
12761
|
const menu = this.renderMenu({
|
|
12728
12762
|
footer,
|
|
12729
12763
|
options,
|
|
12730
|
-
id,
|
|
12731
12764
|
keyboardFocusedOptionIndex,
|
|
12732
12765
|
query,
|
|
12733
12766
|
allowNew,
|
|
@@ -12746,7 +12779,7 @@ class Typeahead extends Component {
|
|
|
12746
12779
|
'typeahead--multiple': multiple,
|
|
12747
12780
|
open: dropdownOpen
|
|
12748
12781
|
}),
|
|
12749
|
-
onClick: stopPropagation
|
|
12782
|
+
onClick: this.stopPropagation,
|
|
12750
12783
|
children: /*#__PURE__*/jsxs("div", {
|
|
12751
12784
|
className: classNames('form-group', {
|
|
12752
12785
|
'has-error': hasError,
|
|
@@ -12767,7 +12800,6 @@ class Typeahead extends Component {
|
|
|
12767
12800
|
placeholder,
|
|
12768
12801
|
selected,
|
|
12769
12802
|
maxHeight,
|
|
12770
|
-
id: id,
|
|
12771
12803
|
name: name,
|
|
12772
12804
|
value: query,
|
|
12773
12805
|
typeaheadId: id,
|
|
@@ -12794,6 +12826,72 @@ class Typeahead extends Component {
|
|
|
12794
12826
|
});
|
|
12795
12827
|
}
|
|
12796
12828
|
}
|
|
12829
|
+
Typeahead.propTypes = {
|
|
12830
|
+
id: PropTypes.string.isRequired,
|
|
12831
|
+
name: PropTypes.string.isRequired,
|
|
12832
|
+
options: PropTypes.arrayOf(PropTypes.shape({
|
|
12833
|
+
label: PropTypes.string.isRequired,
|
|
12834
|
+
note: PropTypes.string,
|
|
12835
|
+
secondary: PropTypes.string,
|
|
12836
|
+
value: PropTypes.object
|
|
12837
|
+
})).isRequired,
|
|
12838
|
+
initialValue: PropTypes.arrayOf(PropTypes.shape({
|
|
12839
|
+
label: PropTypes.string.isRequired,
|
|
12840
|
+
note: PropTypes.string,
|
|
12841
|
+
secondary: PropTypes.string
|
|
12842
|
+
})),
|
|
12843
|
+
onChange: PropTypes.func.isRequired,
|
|
12844
|
+
allowNew: PropTypes.bool,
|
|
12845
|
+
autoFocus: PropTypes.bool,
|
|
12846
|
+
clearable: PropTypes.bool,
|
|
12847
|
+
multiple: PropTypes.bool,
|
|
12848
|
+
showSuggestions: PropTypes.bool,
|
|
12849
|
+
showNewEntry: PropTypes.bool,
|
|
12850
|
+
searchDelay: PropTypes.number,
|
|
12851
|
+
maxHeight: PropTypes.number,
|
|
12852
|
+
minQueryLength: PropTypes.number,
|
|
12853
|
+
addon: PropTypes.node,
|
|
12854
|
+
placeholder: PropTypes.string,
|
|
12855
|
+
alert: PropTypes.shape({
|
|
12856
|
+
message: PropTypes.string.isRequired,
|
|
12857
|
+
type: PropTypes.oneOf(['error', 'warning', 'neutral']).isRequired
|
|
12858
|
+
}),
|
|
12859
|
+
footer: PropTypes.node,
|
|
12860
|
+
validateChip: PropTypes.func,
|
|
12861
|
+
onSearch: PropTypes.func,
|
|
12862
|
+
onBlur: PropTypes.func,
|
|
12863
|
+
onInputChange: PropTypes.func,
|
|
12864
|
+
onFocus: PropTypes.func,
|
|
12865
|
+
chipSeparators: PropTypes.arrayOf(PropTypes.string),
|
|
12866
|
+
size: PropTypes.oneOf(['md', 'lg']),
|
|
12867
|
+
inputAutoComplete: PropTypes.string,
|
|
12868
|
+
autoFillOnBlur: PropTypes.bool
|
|
12869
|
+
};
|
|
12870
|
+
Typeahead.defaultProps = {
|
|
12871
|
+
allowNew: false,
|
|
12872
|
+
autoFocus: false,
|
|
12873
|
+
clearable: true,
|
|
12874
|
+
multiple: false,
|
|
12875
|
+
maxHeight: null,
|
|
12876
|
+
showSuggestions: true,
|
|
12877
|
+
showNewEntry: true,
|
|
12878
|
+
searchDelay: SEARCH_DELAY,
|
|
12879
|
+
minQueryLength: DEFAULT_MIN_QUERY_LENGTH,
|
|
12880
|
+
addon: null,
|
|
12881
|
+
placeholder: null,
|
|
12882
|
+
alert: null,
|
|
12883
|
+
footer: null,
|
|
12884
|
+
size: Size.MEDIUM,
|
|
12885
|
+
chipSeparators: [],
|
|
12886
|
+
initialValue: [],
|
|
12887
|
+
onSearch: null,
|
|
12888
|
+
onBlur: null,
|
|
12889
|
+
onInputChange: null,
|
|
12890
|
+
onFocus: null,
|
|
12891
|
+
validateChip: () => true,
|
|
12892
|
+
inputAutoComplete: 'new-password',
|
|
12893
|
+
autoFillOnBlur: true
|
|
12894
|
+
};
|
|
12797
12895
|
|
|
12798
12896
|
// TODO: consider to move this enum into component file once we migrate it on TypeScript or replace with some common enum
|
|
12799
12897
|
var UploadStep;
|