rsuite 4.8.9 → 4.9.3

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 (49) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/rsuite.js +4744 -2892
  3. package/dist/rsuite.min.js +2 -2
  4. package/dist/rsuite.min.js.map +1 -1
  5. package/dist/styles/rsuite-dark-rtl.css +2 -0
  6. package/dist/styles/rsuite-dark-rtl.min.css +1 -1
  7. package/dist/styles/rsuite-dark-rtl.min.css.map +1 -1
  8. package/dist/styles/rsuite-dark.css +2 -0
  9. package/dist/styles/rsuite-dark.min.css +1 -1
  10. package/dist/styles/rsuite-dark.min.css.map +1 -1
  11. package/dist/styles/rsuite-default-rtl.css +2 -0
  12. package/dist/styles/rsuite-default-rtl.min.css +1 -1
  13. package/dist/styles/rsuite-default-rtl.min.css.map +1 -1
  14. package/dist/styles/rsuite-default.css +2 -0
  15. package/dist/styles/rsuite-default.min.css +1 -1
  16. package/dist/styles/rsuite-default.min.css.map +1 -1
  17. package/es/Footer/Footer.js +1 -1
  18. package/es/InputPicker/InputAutosize.js +3 -1
  19. package/es/InputPicker/InputPicker.js +20 -17
  20. package/es/Nav/Nav.js +5 -4
  21. package/es/Overlay/OverlayTrigger.js +7 -1
  22. package/es/RangeSlider/RangeSlider.js +1 -1
  23. package/es/Uploader/Uploader.d.ts +5 -2
  24. package/es/Uploader/Uploader.js +75 -53
  25. package/es/styles/utilities.less +2 -0
  26. package/lib/Footer/Footer.js +1 -1
  27. package/lib/InputPicker/InputAutosize.js +3 -1
  28. package/lib/InputPicker/InputPicker.js +20 -17
  29. package/lib/Nav/Nav.js +4 -3
  30. package/lib/Overlay/OverlayTrigger.js +7 -1
  31. package/lib/RangeSlider/RangeSlider.js +1 -1
  32. package/lib/Uploader/Uploader.d.ts +5 -2
  33. package/lib/Uploader/Uploader.js +75 -53
  34. package/lib/styles/utilities.less +2 -0
  35. package/package.json +2 -2
  36. package/src/Footer/Footer.tsx +1 -1
  37. package/src/Footer/test/FooterSpec.js +1 -0
  38. package/src/InputPicker/InputAutosize.tsx +3 -1
  39. package/src/InputPicker/InputPicker.tsx +13 -16
  40. package/src/InputPicker/test/InputPickerSpec.js +5 -0
  41. package/src/Nav/Nav.tsx +10 -4
  42. package/src/Nav/test/NavSpec.js +35 -0
  43. package/src/Overlay/OverlayTrigger.tsx +7 -1
  44. package/src/RangeSlider/RangeSlider.tsx +1 -1
  45. package/src/TagPicker/test/TagPickerSpec.js +5 -0
  46. package/src/Uploader/Uploader.d.ts +5 -2
  47. package/src/Uploader/Uploader.tsx +29 -8
  48. package/src/Whisper/test/WhisperSpec.js +46 -1
  49. package/src/styles/utilities.less +2 -0
@@ -70,14 +70,15 @@ function (_React$Component) {
70
70
 
71
71
  (_this$props$onRemove = (_this$props = _this.props).onRemove) === null || _this$props$onRemove === void 0 ? void 0 : _this$props$onRemove.call(_this$props, file);
72
72
  (_this$props$onChange = (_this$props2 = _this.props).onChange) === null || _this$props$onChange === void 0 ? void 0 : _this$props$onChange.call(_this$props2, nextFileList);
73
+
74
+ _this.cleanInputValue();
73
75
  };
74
76
 
75
77
  _this.handleUploadTriggerChange = function (event) {
76
- var _this$props$onChange2, _this$props4;
77
-
78
78
  var _this$props3 = _this.props,
79
79
  autoUpload = _this$props3.autoUpload,
80
- shouldQueueUpdate = _this$props3.shouldQueueUpdate;
80
+ shouldQueueUpdate = _this$props3.shouldQueueUpdate,
81
+ onChange = _this$props3.onChange;
81
82
 
82
83
  var fileList = _this.getFileList();
83
84
 
@@ -92,20 +93,32 @@ function (_React$Component) {
92
93
  });
93
94
  });
94
95
  var nextFileList = [].concat(fileList, newFileList);
96
+ var checkState = shouldQueueUpdate === null || shouldQueueUpdate === void 0 ? void 0 : shouldQueueUpdate(nextFileList, newFileList);
97
+
98
+ var upload = function upload() {
99
+ onChange === null || onChange === void 0 ? void 0 : onChange(nextFileList);
100
+
101
+ _this.setState({
102
+ fileList: nextFileList
103
+ }, function () {
104
+ autoUpload && _this.handleAjaxUpload();
105
+ });
106
+ };
95
107
 
96
- if ((shouldQueueUpdate === null || shouldQueueUpdate === void 0 ? void 0 : shouldQueueUpdate(nextFileList, newFileList)) === false) {
108
+ if (checkState instanceof Promise) {
109
+ checkState.then(function (res) {
110
+ if (res) {
111
+ upload();
112
+ }
113
+ });
114
+ return;
115
+ } else if (checkState === false) {
97
116
  _this.cleanInputValue();
98
117
 
99
118
  return;
100
119
  }
101
120
 
102
- (_this$props$onChange2 = (_this$props4 = _this.props).onChange) === null || _this$props$onChange2 === void 0 ? void 0 : _this$props$onChange2.call(_this$props4, nextFileList);
103
-
104
- _this.setState({
105
- fileList: nextFileList
106
- }, function () {
107
- autoUpload && _this.handleAjaxUpload();
108
- });
121
+ upload();
109
122
  };
110
123
 
111
124
  _this.handleAjaxUploadSuccess = function (file, response, event, xhr) {
@@ -115,9 +128,9 @@ function (_React$Component) {
115
128
  });
116
129
 
117
130
  _this.updateFileList(nextFile, function () {
118
- var _this$props$onSuccess, _this$props5;
131
+ var _this$props$onSuccess, _this$props4;
119
132
 
120
- (_this$props$onSuccess = (_this$props5 = _this.props).onSuccess) === null || _this$props$onSuccess === void 0 ? void 0 : _this$props$onSuccess.call(_this$props5, response, nextFile, event, xhr);
133
+ (_this$props$onSuccess = (_this$props4 = _this.props).onSuccess) === null || _this$props$onSuccess === void 0 ? void 0 : _this$props$onSuccess.call(_this$props4, response, nextFile, event, xhr);
121
134
  });
122
135
  };
123
136
 
@@ -127,9 +140,9 @@ function (_React$Component) {
127
140
  });
128
141
 
129
142
  _this.updateFileList(nextFile, function () {
130
- var _this$props$onError, _this$props6;
143
+ var _this$props$onError, _this$props5;
131
144
 
132
- (_this$props$onError = (_this$props6 = _this.props).onError) === null || _this$props$onError === void 0 ? void 0 : _this$props$onError.call(_this$props6, status, nextFile, event, xhr);
145
+ (_this$props$onError = (_this$props5 = _this.props).onError) === null || _this$props$onError === void 0 ? void 0 : _this$props$onError.call(_this$props5, status, nextFile, event, xhr);
133
146
  });
134
147
  };
135
148
 
@@ -140,21 +153,21 @@ function (_React$Component) {
140
153
  });
141
154
 
142
155
  _this.updateFileList(nextFile, function () {
143
- var _this$props$onProgres, _this$props7;
156
+ var _this$props$onProgres, _this$props6;
144
157
 
145
- (_this$props$onProgres = (_this$props7 = _this.props).onProgress) === null || _this$props$onProgres === void 0 ? void 0 : _this$props$onProgres.call(_this$props7, percent, nextFile, event, xhr);
158
+ (_this$props$onProgres = (_this$props6 = _this.props).onProgress) === null || _this$props$onProgres === void 0 ? void 0 : _this$props$onProgres.call(_this$props6, percent, nextFile, event, xhr);
146
159
  });
147
160
  };
148
161
 
149
162
  _this.handleUploadFile = function (file) {
150
- var _this$props8 = _this.props,
151
- name = _this$props8.name,
152
- action = _this$props8.action,
153
- headers = _this$props8.headers,
154
- withCredentials = _this$props8.withCredentials,
155
- timeout = _this$props8.timeout,
156
- data = _this$props8.data,
157
- onUpload = _this$props8.onUpload;
163
+ var _this$props7 = _this.props,
164
+ name = _this$props7.name,
165
+ action = _this$props7.action,
166
+ headers = _this$props7.headers,
167
+ withCredentials = _this$props7.withCredentials,
168
+ timeout = _this$props7.timeout,
169
+ data = _this$props7.data,
170
+ onUpload = _this$props7.onUpload;
158
171
  var xhr = (0, _utils.ajaxUpload)({
159
172
  name: name,
160
173
  timeout: timeout,
@@ -177,9 +190,9 @@ function (_React$Component) {
177
190
  };
178
191
 
179
192
  _this.handleReupload = function (file) {
180
- var _this$props9 = _this.props,
181
- onReupload = _this$props9.onReupload,
182
- autoUpload = _this$props9.autoUpload;
193
+ var _this$props8 = _this.props,
194
+ onReupload = _this$props8.onReupload,
195
+ autoUpload = _this$props8.autoUpload;
183
196
  autoUpload && _this.handleUploadFile(file);
184
197
  onReupload === null || onReupload === void 0 ? void 0 : onReupload(file);
185
198
  };
@@ -249,7 +262,16 @@ function (_React$Component) {
249
262
  var shouldUpload = this.props.shouldUpload;
250
263
  var fileList = this.getFileList();
251
264
  fileList.forEach(function (file) {
252
- if ((shouldUpload === null || shouldUpload === void 0 ? void 0 : shouldUpload(file)) === false) {
265
+ var checkState = shouldUpload === null || shouldUpload === void 0 ? void 0 : shouldUpload(file);
266
+
267
+ if (checkState instanceof Promise) {
268
+ checkState.then(function (res) {
269
+ if (res) {
270
+ _this2.handleUploadFile(file);
271
+ }
272
+ });
273
+ return;
274
+ } else if (checkState === false) {
253
275
  return;
254
276
  }
255
277
 
@@ -284,13 +306,13 @@ function (_React$Component) {
284
306
  _proto.renderFileItems = function renderFileItems() {
285
307
  var _this3 = this;
286
308
 
287
- var _this$props10 = this.props,
288
- disabledFileItem = _this$props10.disabledFileItem,
289
- listType = _this$props10.listType,
290
- onPreview = _this$props10.onPreview,
291
- maxPreviewFileSize = _this$props10.maxPreviewFileSize,
292
- renderFileInfo = _this$props10.renderFileInfo,
293
- removable = _this$props10.removable;
309
+ var _this$props9 = this.props,
310
+ disabledFileItem = _this$props9.disabledFileItem,
311
+ listType = _this$props9.listType,
312
+ onPreview = _this$props9.onPreview,
313
+ maxPreviewFileSize = _this$props9.maxPreviewFileSize,
314
+ renderFileInfo = _this$props9.renderFileInfo,
315
+ removable = _this$props9.removable;
294
316
  var fileList = this.getFileList();
295
317
  return React.createElement("div", {
296
318
  key: "items",
@@ -312,15 +334,15 @@ function (_React$Component) {
312
334
  };
313
335
 
314
336
  _proto.renderUploadTrigger = function renderUploadTrigger() {
315
- var _this$props11 = this.props,
316
- name = _this$props11.name,
317
- multiple = _this$props11.multiple,
318
- disabled = _this$props11.disabled,
319
- accept = _this$props11.accept,
320
- children = _this$props11.children,
321
- toggleComponentClass = _this$props11.toggleComponentClass,
322
- draggable = _this$props11.draggable,
323
- rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props11, ["name", "multiple", "disabled", "accept", "children", "toggleComponentClass", "draggable"]);
337
+ var _this$props10 = this.props,
338
+ name = _this$props10.name,
339
+ multiple = _this$props10.multiple,
340
+ disabled = _this$props10.disabled,
341
+ accept = _this$props10.accept,
342
+ children = _this$props10.children,
343
+ toggleComponentClass = _this$props10.toggleComponentClass,
344
+ draggable = _this$props10.draggable,
345
+ rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props10, ["name", "multiple", "disabled", "accept", "children", "toggleComponentClass", "draggable"]);
324
346
  var unhandled = (0, _utils.getUnhandledProps)(Uploader, rest);
325
347
  return React.createElement(_UploadTrigger.default, (0, _extends2.default)({}, unhandled, {
326
348
  name: name,
@@ -338,14 +360,14 @@ function (_React$Component) {
338
360
  _proto.render = function render() {
339
361
  var _classNames;
340
362
 
341
- var _this$props12 = this.props,
342
- classPrefix = _this$props12.classPrefix,
343
- className = _this$props12.className,
344
- listType = _this$props12.listType,
345
- fileListVisible = _this$props12.fileListVisible,
346
- locale = _this$props12.locale,
347
- style = _this$props12.style,
348
- draggable = _this$props12.draggable;
363
+ var _this$props11 = this.props,
364
+ classPrefix = _this$props11.classPrefix,
365
+ className = _this$props11.className,
366
+ listType = _this$props11.listType,
367
+ fileListVisible = _this$props11.fileListVisible,
368
+ locale = _this$props11.locale,
369
+ style = _this$props11.style,
370
+ draggable = _this$props11.draggable;
349
371
  var classes = (0, _classnames.default)(className, classPrefix, this.addPrefix(listType), (_classNames = {}, _classNames[this.addPrefix('draggable')] = draggable, _classNames));
350
372
  var renderList = [this.renderUploadTrigger()];
351
373
 
@@ -44,9 +44,11 @@
44
44
  .fade {
45
45
  opacity: 0;
46
46
  transition: opacity 0.15s linear;
47
+ pointer-events: none;
47
48
 
48
49
  &.in {
49
50
  opacity: 1;
51
+ pointer-events: unset;
50
52
  }
51
53
  }
52
54
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsuite",
3
- "version": "4.8.9",
3
+ "version": "4.9.3",
4
4
  "description": "A suite of react components",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -63,7 +63,7 @@
63
63
  "react-lifecycles-compat": "^3.0.4",
64
64
  "react-virtualized": "^9.21.0",
65
65
  "recompose": "^0.30.0",
66
- "rsuite-table": "^3.14.3",
66
+ "rsuite-table": "^3.14.4",
67
67
  "schema-typed": "^1.5.1"
68
68
  },
69
69
  "peerDependencies": {
@@ -13,7 +13,7 @@ class Footer extends React.Component<FooterProps> {
13
13
  const { className, classPrefix, ...props } = this.props;
14
14
  const classes = classNames(classPrefix, className);
15
15
 
16
- return <div {...props} className={classes} />;
16
+ return <footer {...props} className={classes} />;
17
17
  }
18
18
  }
19
19
 
@@ -6,6 +6,7 @@ describe('Footer', () => {
6
6
  it('Should render a Footer', () => {
7
7
  const title = 'Test';
8
8
  const instance = getDOMNode(<Footer>{title}</Footer>);
9
+ assert.equal(instance.tagName, 'FOOTER');
9
10
  assert.include(instance.className, 'rs-footer');
10
11
  assert.equal(innerText(instance), title);
11
12
  });
@@ -158,7 +158,8 @@ class InputAutosize extends React.Component<InputAutosizeProps, InputAutosizeSta
158
158
  className,
159
159
  placeholder,
160
160
  inputClassName,
161
- inputStyle
161
+ inputStyle,
162
+ tabIndex
162
163
  } = this.props;
163
164
 
164
165
  const inputId = this.getInputId();
@@ -185,6 +186,7 @@ class InputAutosize extends React.Component<InputAutosizeProps, InputAutosizeSta
185
186
  htmlInputProps.className = inputClassName;
186
187
  htmlInputProps.id = inputId || inputId;
187
188
  htmlInputProps.style = nextInputStyle;
189
+ htmlInputProps.tabIndex = tabIndex;
188
190
 
189
191
  return (
190
192
  <div className={className} style={wrapperStyle}>
@@ -472,20 +472,11 @@ class InputPicker extends React.Component<InputPickerProps, InputPickerState> {
472
472
  const { onClose, multi } = this.props;
473
473
  const value: any = this.getValue();
474
474
 
475
- const nextState: InputPickerState = {
476
- focusItemValue: multi ? _.get(value, 0) : value
477
- };
478
-
479
- if (multi) {
480
- /**
481
- 在多选的情况下, 当 searchKeyword 过长,在 focus 的时候会导致内容换行。
482
- 把 searchKeyword 清空是为了,Menu 在展开时候位置正确。
483
- */
484
- nextState.searchKeyword = '';
485
- }
486
-
487
475
  onClose?.();
488
- this.setState(nextState);
476
+ this.setState({
477
+ focusItemValue: multi ? _.get(value, 0) : value,
478
+ searchKeyword: ''
479
+ });
489
480
  };
490
481
 
491
482
  handleEnter = () => {
@@ -506,6 +497,11 @@ class InputPicker extends React.Component<InputPickerProps, InputPickerState> {
506
497
  this.handleChange(value, event);
507
498
  };
508
499
 
500
+ handleInputFocus = () => {
501
+ this.setState({ open: true });
502
+ this.triggerRef.current?.show();
503
+ };
504
+
509
505
  removeLastItem = (event: React.KeyboardEvent<HTMLInputElement>) => {
510
506
  const tagName = _.get(event, 'target.tagName');
511
507
  if (tagName !== 'INPUT') {
@@ -665,10 +661,8 @@ class InputPicker extends React.Component<InputPickerProps, InputPickerState> {
665
661
  }
666
662
 
667
663
  renderInputSearch() {
668
- const { multi, onBlur, onFocus } = this.props;
664
+ const { multi, onBlur, onFocus, tabIndex } = this.props;
669
665
  const props: any = {
670
- onBlur,
671
- onFocus,
672
666
  componentClass: 'input',
673
667
  inputRef: this.inputRef
674
668
  };
@@ -682,8 +676,11 @@ class InputPicker extends React.Component<InputPickerProps, InputPickerState> {
682
676
  return (
683
677
  <InputSearch
684
678
  {...props}
679
+ tabIndex={tabIndex}
685
680
  onChange={this.handleSearch}
686
681
  value={this.state.open ? this.state.searchKeyword : ''}
682
+ onBlur={onBlur}
683
+ onFocus={createChainedFunction(this.handleInputFocus, onFocus)}
687
684
  />
688
685
  );
689
686
  }
@@ -321,4 +321,9 @@ describe('InputPicker', () => {
321
321
  assert.equal(instance2.querySelector('.rs-picker-toggle-placeholder').innerText, 'Select');
322
322
  assert.equal(instance3.querySelector('.rs-picker-toggle-placeholder').innerText, 'Select');
323
323
  });
324
+
325
+ it('Should set a tabindex for input', () => {
326
+ const instance = getDOMNode(<InputPicker tabIndex={10} />);
327
+ assert.equal(instance.querySelector('.rs-picker-search-input').getAttribute('tabindex'), '10');
328
+ });
324
329
  });
package/src/Nav/Nav.tsx CHANGED
@@ -5,7 +5,13 @@ import { setStatic } from 'recompose';
5
5
  import shallowEqual from '../utils/shallowEqual';
6
6
 
7
7
  import NavItem from './NavItem';
8
- import { prefix, getUnhandledProps, defaultProps, ReactChildren } from '../utils';
8
+ import {
9
+ prefix,
10
+ getUnhandledProps,
11
+ defaultProps,
12
+ ReactChildren,
13
+ createChainedFunction
14
+ } from '../utils';
9
15
  import { getClassNamePrefix } from '../utils/prefix';
10
16
  import { NavbarContext } from '../Navbar/Navbar';
11
17
  import { SidenavContext } from '../Sidenav/Sidenav';
@@ -56,21 +62,21 @@ class Nav extends React.Component<NavProps> {
56
62
  const hasWaterline = appearance !== 'default';
57
63
 
58
64
  const items = ReactChildren.mapCloneElement(children, item => {
59
- const { eventKey, active, ...rest } = item.props;
65
+ const { eventKey, active, onSelect: onSelectItem, ...rest } = item.props;
60
66
  const displayName = item?.type?.displayName;
61
67
  const hasTooltip = sidenav && !expanded;
62
68
 
63
69
  if (~displayName?.indexOf('(NavItem)')) {
64
70
  return {
65
71
  ...rest,
66
- onSelect,
72
+ onSelect: createChainedFunction(onSelect, onSelectItem),
67
73
  hasTooltip,
68
74
  active: typeof activeKey === 'undefined' ? active : shallowEqual(activeKey, eventKey)
69
75
  };
70
76
  } else if (~displayName?.indexOf('(Dropdown)')) {
71
77
  return {
72
78
  ...rest,
73
- onSelect,
79
+ onSelect: createChainedFunction(onSelect, onSelectItem),
74
80
  activeKey,
75
81
  showHeader: hasTooltip,
76
82
  componentClass: 'li'
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import ReactTestUtils from 'react-dom/test-utils';
2
3
  import { innerText, getDOMNode } from '@test/testUtils';
3
4
 
4
5
  import Nav from '../Nav';
@@ -68,4 +69,38 @@ describe('Nav', () => {
68
69
  const instance = getDOMNode(<Nav classPrefix="custom-prefix" />);
69
70
  assert.ok(instance.className.match(/\bcustom-prefix\b/));
70
71
  });
72
+
73
+ it('Should call onSelect callback', done => {
74
+ const doneOp = eventKey => {
75
+ if (eventKey === 2) {
76
+ done();
77
+ }
78
+ };
79
+ const instance = getDOMNode(
80
+ <Nav onSelect={doneOp}>
81
+ <Nav.Item eventKey={1}>1</Nav.Item>
82
+ <Nav.Item eventKey={2}>2</Nav.Item>
83
+ </Nav>
84
+ );
85
+
86
+ ReactTestUtils.Simulate.click(instance.querySelectorAll('.rs-nav-item a')[1]);
87
+ });
88
+
89
+ it('Should call onSelect callback on Nav.Item', done => {
90
+ const doneOp = eventKey => {
91
+ if (eventKey === 2) {
92
+ done();
93
+ }
94
+ };
95
+ const instance = getDOMNode(
96
+ <Nav>
97
+ <Nav.Item eventKey={1}>1</Nav.Item>
98
+ <Nav.Item eventKey={2} onSelect={doneOp}>
99
+ 2
100
+ </Nav.Item>
101
+ </Nav>
102
+ );
103
+
104
+ ReactTestUtils.Simulate.click(instance.querySelectorAll('.rs-nav-item a')[1]);
105
+ });
71
106
  });
@@ -211,7 +211,13 @@ class OverlayTrigger extends React.Component<OverlayTriggerProps, OverlayTrigger
211
211
  }
212
212
 
213
213
  if (typeof speaker === 'function') {
214
- return <Overlay {...overlayProps}>{speaker}</Overlay>;
214
+ return (
215
+ <Overlay {...overlayProps}>
216
+ {(props, ref) => {
217
+ return speaker({ ...props, onClose: this.hide }, ref);
218
+ }}
219
+ </Overlay>
220
+ );
215
221
  }
216
222
 
217
223
  return <Overlay {...overlayProps}>{React.cloneElement(speaker, speakerProps)}</Overlay>;
@@ -146,7 +146,7 @@ class RangeSlider extends React.Component<RangeSliderProps, RangeSliderState> {
146
146
  end = value;
147
147
  }
148
148
 
149
- this.setValue([start, end], event);
149
+ this.setValue([start, end].sort() as ValueType, event);
150
150
  };
151
151
 
152
152
  handleDragMove = (key: 'start' | 'end', event: React.MouseEvent) => {
@@ -351,4 +351,9 @@ describe('TagPicker', () => {
351
351
  assert.equal(instance2.querySelector('.rs-picker-toggle-placeholder').innerText, 'Select');
352
352
  assert.equal(instance3.querySelector('.rs-picker-toggle-placeholder').innerText, 'Select');
353
353
  });
354
+
355
+ it('Should set a tabindex for input', () => {
356
+ const instance = getDOMNode(<TagPicker tabIndex={10} />);
357
+ assert.equal(instance.querySelector('input[type="text"]').getAttribute('tabindex'), '10');
358
+ });
354
359
  });
@@ -67,10 +67,13 @@ export interface UploaderProps extends StandardProps {
67
67
  listType?: 'text' | 'picture-text' | 'picture';
68
68
 
69
69
  /** Allow the queue to be updated. After you select a file, update the checksum function before the upload file queue, and return false to not update */
70
- shouldQueueUpdate?: (fileList: FileType[], newFile: FileType[] | FileType) => boolean;
70
+ shouldQueueUpdate?: (
71
+ fileList: FileType[],
72
+ newFile: FileType[] | FileType
73
+ ) => boolean | Promise<boolean>;
71
74
 
72
75
  /** Allow uploading of files. Check function before file upload, return false without uploading */
73
- shouldUpload?: (file: FileType) => boolean;
76
+ shouldUpload?: (file: FileType) => boolean | Promise<boolean>;
74
77
 
75
78
  /** callback function that the upload queue has changed */
76
79
  onChange?: (fileList: FileType[]) => void;
@@ -132,10 +132,11 @@ class Uploader extends React.Component<UploaderProps, UploaderState> {
132
132
 
133
133
  this.props.onRemove?.(file);
134
134
  this.props.onChange?.(nextFileList);
135
+ this.cleanInputValue();
135
136
  };
136
137
 
137
138
  handleUploadTriggerChange = (event: React.ChangeEvent<HTMLInputElement>) => {
138
- const { autoUpload, shouldQueueUpdate } = this.props;
139
+ const { autoUpload, shouldQueueUpdate, onChange } = this.props;
139
140
  const fileList = this.getFileList();
140
141
  const files: File[] = getFiles(event);
141
142
  const newFileList: FileType[] = [];
@@ -150,23 +151,42 @@ class Uploader extends React.Component<UploaderProps, UploaderState> {
150
151
  });
151
152
 
152
153
  const nextFileList = [...fileList, ...newFileList];
154
+ const checkState = shouldQueueUpdate?.(nextFileList, newFileList);
155
+ const upload = () => {
156
+ onChange?.(nextFileList);
157
+ this.setState({ fileList: nextFileList }, () => {
158
+ autoUpload && this.handleAjaxUpload();
159
+ });
160
+ };
153
161
 
154
- if (shouldQueueUpdate?.(nextFileList, newFileList) === false) {
162
+ if (checkState instanceof Promise) {
163
+ checkState.then(res => {
164
+ if (res) {
165
+ upload();
166
+ }
167
+ });
168
+ return;
169
+ } else if (checkState === false) {
155
170
  this.cleanInputValue();
156
171
  return;
157
172
  }
158
-
159
- this.props.onChange?.(nextFileList);
160
- this.setState({ fileList: nextFileList }, () => {
161
- autoUpload && this.handleAjaxUpload();
162
- });
173
+ upload();
163
174
  };
164
175
 
165
176
  handleAjaxUpload() {
166
177
  const { shouldUpload } = this.props;
167
178
  const fileList = this.getFileList();
168
179
  fileList.forEach(file => {
169
- if (shouldUpload?.(file) === false) {
180
+ const checkState = shouldUpload?.(file);
181
+
182
+ if (checkState instanceof Promise) {
183
+ checkState.then(res => {
184
+ if (res) {
185
+ this.handleUploadFile(file);
186
+ }
187
+ });
188
+ return;
189
+ } else if (checkState === false) {
170
190
  return;
171
191
  }
172
192
 
@@ -336,6 +356,7 @@ class Uploader extends React.Component<UploaderProps, UploaderState> {
336
356
  ...rest
337
357
  } = this.props;
338
358
  const unhandled = getUnhandledProps(Uploader, rest);
359
+
339
360
  return (
340
361
  <UploadTrigger
341
362
  {...unhandled}
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
+ import ReactDOM from 'react-dom';
2
3
  import ReactTestUtils from 'react-dom/test-utils';
3
- import { getDOMNode } from '@test/testUtils';
4
+ import { getDOMNode, createTestContainer } from '@test/testUtils';
4
5
 
5
6
  import Whisper from '../Whisper';
6
7
  import Tooltip from '../../Tooltip';
@@ -166,4 +167,48 @@ describe('Whisper', () => {
166
167
 
167
168
  ReactTestUtils.Simulate.click(whisper);
168
169
  });
170
+
171
+ it('Should Overlay be closed, after call onClose', done => {
172
+ const doneOp = () => {
173
+ done();
174
+ };
175
+ const btnRef = React.createRef();
176
+ const closeBtnRef = React.createRef();
177
+ const Overlay = React.forwardRef(({ style, onClose, ...rest }, ref) => {
178
+ return (
179
+ <div {...rest} style={style} ref={ref}>
180
+ <button ref={closeBtnRef} onClick={onClose}>
181
+ close
182
+ </button>
183
+ </div>
184
+ );
185
+ });
186
+
187
+ Overlay.displayName = 'Overlay';
188
+
189
+ ReactTestUtils.act(() => {
190
+ ReactDOM.render(
191
+ <Whisper
192
+ onExited={doneOp}
193
+ trigger="click"
194
+ speaker={(props, ref) => {
195
+ const { className, left, top, onClose } = props;
196
+ return (
197
+ <Overlay style={{ left, top }} onClose={onClose} className={className} ref={ref} />
198
+ );
199
+ }}
200
+ >
201
+ <button ref={btnRef}>button</button>
202
+ </Whisper>,
203
+ createTestContainer()
204
+ );
205
+ });
206
+ ReactTestUtils.act(() => {
207
+ ReactTestUtils.Simulate.click(btnRef.current);
208
+ });
209
+
210
+ ReactTestUtils.act(() => {
211
+ ReactTestUtils.Simulate.click(closeBtnRef.current);
212
+ });
213
+ });
169
214
  });
@@ -44,9 +44,11 @@
44
44
  .fade {
45
45
  opacity: 0;
46
46
  transition: opacity 0.15s linear;
47
+ pointer-events: none;
47
48
 
48
49
  &.in {
49
50
  opacity: 1;
51
+ pointer-events: unset;
50
52
  }
51
53
  }
52
54