rsuite 4.10.5 → 4.10.8

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.
@@ -510,9 +510,7 @@ function (_React$Component) {
510
510
  };
511
511
 
512
512
  _proto.updateDataChange = function updateDataChange(prevState) {
513
- var _this$state2 = this.state,
514
- searchKeyword = _this$state2.searchKeyword,
515
- expandItemValues = _this$state2.expandItemValues;
513
+ var searchKeyword = this.state.searchKeyword;
516
514
  var _this$props7 = this.props,
517
515
  _this$props7$data = _this$props7.data,
518
516
  data = _this$props7$data === void 0 ? [] : _this$props7$data,
@@ -523,8 +521,7 @@ function (_React$Component) {
523
521
  this.nodes = {};
524
522
  this.flattenNodes(nextData);
525
523
  this.unserializeLists({
526
- check: this.getValue(),
527
- expand: expandItemValues
524
+ check: this.getValue()
528
525
  });
529
526
  this.setState({
530
527
  data: nextData,
@@ -567,10 +564,10 @@ function (_React$Component) {
567
564
  };
568
565
 
569
566
  _proto.updateUncheckableItemValuesChange = function updateUncheckableItemValuesChange(prevState) {
570
- var _this$state3 = this.state,
571
- data = _this$state3.data,
572
- selectedValues = _this$state3.selectedValues,
573
- expandItemValues = _this$state3.expandItemValues;
567
+ var _this$state2 = this.state,
568
+ data = _this$state2.data,
569
+ selectedValues = _this$state2.selectedValues,
570
+ expandItemValues = _this$state2.expandItemValues;
574
571
  var uncheckableItemValues = this.props.uncheckableItemValues;
575
572
 
576
573
  if (compareArray(uncheckableItemValues, prevState.uncheckableItemValues) && _isArray(uncheckableItemValues)) {
@@ -586,10 +583,10 @@ function (_React$Component) {
586
583
  };
587
584
 
588
585
  _proto.updateCascadeChange = function updateCascadeChange(prevState) {
589
- var _this$state4 = this.state,
590
- data = _this$state4.data,
591
- selectedValues = _this$state4.selectedValues,
592
- expandItemValues = _this$state4.expandItemValues;
586
+ var _this$state3 = this.state,
587
+ data = _this$state3.data,
588
+ selectedValues = _this$state3.selectedValues,
589
+ expandItemValues = _this$state3.expandItemValues;
593
590
  var cascade = this.props.cascade; // cascade 改变时,重新初始化
594
591
 
595
592
  if (cascade !== prevState.cascade && cascade) {
@@ -1062,9 +1059,9 @@ function (_React$Component) {
1062
1059
  _proto.renderNode = function renderNode(node, layer) {
1063
1060
  var _this10 = this;
1064
1061
 
1065
- var _this$state5 = this.state,
1066
- activeNode = _this$state5.activeNode,
1067
- searchKeyword = _this$state5.searchKeyword;
1062
+ var _this$state4 = this.state,
1063
+ activeNode = _this$state4.activeNode,
1064
+ searchKeyword = _this$state4.searchKeyword;
1068
1065
  var _this$props11 = this.props,
1069
1066
  valueKey = _this$props11.valueKey,
1070
1067
  labelKey = _this$props11.labelKey,
@@ -1132,10 +1129,10 @@ function (_React$Component) {
1132
1129
  };
1133
1130
 
1134
1131
  _proto.renderVirtualNode = function renderVirtualNode(node, options) {
1135
- var _this$state6 = this.state,
1136
- activeNode = _this$state6.activeNode,
1137
- expandAll = _this$state6.expandAll,
1138
- searchKeyword = _this$state6.searchKeyword;
1132
+ var _this$state5 = this.state,
1133
+ activeNode = _this$state5.activeNode,
1134
+ expandAll = _this$state5.expandAll,
1135
+ searchKeyword = _this$state5.searchKeyword;
1139
1136
  var _this$props12 = this.props,
1140
1137
  valueKey = _this$props12.valueKey,
1141
1138
  labelKey = _this$props12.labelKey,
@@ -1185,9 +1182,9 @@ function (_React$Component) {
1185
1182
  _this11 = this,
1186
1183
  _classNames3;
1187
1184
 
1188
- var _this$state7 = this.state,
1189
- filterData = _this$state7.filterData,
1190
- isSomeNodeHasChildren = _this$state7.isSomeNodeHasChildren;
1185
+ var _this$state6 = this.state,
1186
+ filterData = _this$state6.filterData,
1187
+ isSomeNodeHasChildren = _this$state6.isSomeNodeHasChildren;
1191
1188
  var _this$props13 = this.props,
1192
1189
  inline = _this$props13.inline,
1193
1190
  style = _this$props13.style,
@@ -1279,9 +1276,9 @@ function (_React$Component) {
1279
1276
  positionRef = _this$props14.positionRef,
1280
1277
  rest = _objectWithoutPropertiesLoose(_this$props14, ["cascade", "style", "locale", "inline", "disabled", "valueKey", "labelKey", "cleanable", "countable", "placeholder", "toggleComponentClass", "onExited", "onEntered", "onClean", "renderValue", "positionRef"]);
1281
1278
 
1282
- var _this$state8 = this.state,
1283
- hasValue = _this$state8.hasValue,
1284
- selectedValues = _this$state8.selectedValues;
1279
+ var _this$state7 = this.state,
1280
+ hasValue = _this$state7.hasValue,
1281
+ selectedValues = _this$state7.selectedValues;
1285
1282
 
1286
1283
  var hasValidValue = hasValue || selectedValues.length > 0 && _isFunction(renderValue);
1287
1284
 
@@ -164,6 +164,17 @@ function (_React$Component) {
164
164
  }
165
165
  };
166
166
 
167
+ _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
168
+ var preValue = prevProps.value;
169
+ var currentValue = this.props.value;
170
+
171
+ if (preValue !== currentValue) {
172
+ this.setState({
173
+ value: currentValue
174
+ });
175
+ }
176
+ };
177
+
167
178
  _proto.getValue = function getValue() {
168
179
  var value = this.props.value;
169
180
  return _isUndefined(value) ? this.state.value : value;
@@ -48,6 +48,7 @@ function (_React$Component2) {
48
48
  _this.lastFocus = null;
49
49
  _this.onDocumentKeyupListener = null;
50
50
  _this.onFocusinListener = null;
51
+ _this._isMounted = null;
51
52
 
52
53
  _this.setMountNodeRef = function (ref) {
53
54
  var _ref$getMountNode;
@@ -95,15 +96,30 @@ function (_React$Component2) {
95
96
  _this.enforceFocus = function () {
96
97
  var enforceFocus = _this.props.enforceFocus;
97
98
 
98
- if (!enforceFocus || !_this.isTopModal()) {
99
+ if (!enforceFocus || !_this._isMounted || !_this.isTopModal()) {
99
100
  return;
100
101
  }
101
102
 
102
- var active = activeElement(ownerDocument(_assertThisInitialized(_this)));
103
+ var currentActiveElement = activeElement(ownerDocument(_assertThisInitialized(_this)));
103
104
 
104
105
  var modal = _this.getDialogElement();
105
106
 
106
- if (modal && modal !== active && !contains(modal, active)) {
107
+ if (modal && modal !== currentActiveElement && !contains(modal, currentActiveElement)) {
108
+ modal.focus();
109
+ }
110
+ };
111
+
112
+ _this.handlePortalRendered = function () {
113
+ if (!_this.props.autoFocus) {
114
+ return;
115
+ }
116
+
117
+ var modal = _this.getDialogElement();
118
+
119
+ var currentActiveElement = activeElement(ownerDocument(_assertThisInitialized(_this)));
120
+
121
+ if (modal && modal !== currentActiveElement && !contains(modal, currentActiveElement)) {
122
+ _this.lastFocus = currentActiveElement;
107
123
  modal.focus();
108
124
  }
109
125
  };
@@ -120,6 +136,8 @@ function (_React$Component2) {
120
136
  var _proto2 = BaseModal.prototype;
121
137
 
122
138
  _proto2.componentDidMount = function componentDidMount() {
139
+ this._isMounted = true;
140
+
123
141
  if (this.props.show) {
124
142
  this.onShow();
125
143
  }
@@ -163,6 +181,7 @@ function (_React$Component2) {
163
181
  var _this$props4 = this.props,
164
182
  show = _this$props4.show,
165
183
  transition = _this$props4.transition;
184
+ this._isMounted = false;
166
185
 
167
186
  if (show || transition && !this.state.exited) {
168
187
  this.onHide();
@@ -293,7 +312,8 @@ function (_React$Component2) {
293
312
 
294
313
  return React.createElement(Portal, {
295
314
  ref: this.setMountNodeRef,
296
- container: container
315
+ container: container,
316
+ onRendered: this.handlePortalRendered
297
317
  }, React.createElement("div", {
298
318
  ref: this.modalNodeRef,
299
319
  role: rest.role,
@@ -66,6 +66,7 @@ function (_React$Component) {
66
66
  return React.createElement("div", _extends({}, props, {
67
67
  title: null,
68
68
  role: "dialog",
69
+ tabIndex: -1,
69
70
  ref: mergeRefs(this.bindHtmlRef, dialogRef),
70
71
  className: classNames(classPrefix, className),
71
72
  style: modalStyle
@@ -544,9 +544,7 @@ function (_React$Component) {
544
544
  };
545
545
 
546
546
  _proto.updateDataChange = function updateDataChange(prevState) {
547
- var _this$state2 = this.state,
548
- searchKeyword = _this$state2.searchKeyword,
549
- expandItemValues = _this$state2.expandItemValues;
547
+ var searchKeyword = this.state.searchKeyword;
550
548
  var _this$props7 = this.props,
551
549
  _this$props7$data = _this$props7.data,
552
550
  data = _this$props7$data === void 0 ? [] : _this$props7$data,
@@ -557,8 +555,7 @@ function (_React$Component) {
557
555
  this.nodes = {};
558
556
  this.flattenNodes(nextData);
559
557
  this.unserializeLists({
560
- check: this.getValue(),
561
- expand: expandItemValues
558
+ check: this.getValue()
562
559
  });
563
560
  this.setState({
564
561
  data: nextData,
@@ -601,10 +598,10 @@ function (_React$Component) {
601
598
  };
602
599
 
603
600
  _proto.updateUncheckableItemValuesChange = function updateUncheckableItemValuesChange(prevState) {
604
- var _this$state3 = this.state,
605
- data = _this$state3.data,
606
- selectedValues = _this$state3.selectedValues,
607
- expandItemValues = _this$state3.expandItemValues;
601
+ var _this$state2 = this.state,
602
+ data = _this$state2.data,
603
+ selectedValues = _this$state2.selectedValues,
604
+ expandItemValues = _this$state2.expandItemValues;
608
605
  var uncheckableItemValues = this.props.uncheckableItemValues;
609
606
 
610
607
  if ((0, _treeUtils.compareArray)(uncheckableItemValues, prevState.uncheckableItemValues) && (0, _isArray2.default)(uncheckableItemValues)) {
@@ -620,10 +617,10 @@ function (_React$Component) {
620
617
  };
621
618
 
622
619
  _proto.updateCascadeChange = function updateCascadeChange(prevState) {
623
- var _this$state4 = this.state,
624
- data = _this$state4.data,
625
- selectedValues = _this$state4.selectedValues,
626
- expandItemValues = _this$state4.expandItemValues;
620
+ var _this$state3 = this.state,
621
+ data = _this$state3.data,
622
+ selectedValues = _this$state3.selectedValues,
623
+ expandItemValues = _this$state3.expandItemValues;
627
624
  var cascade = this.props.cascade; // cascade 改变时,重新初始化
628
625
 
629
626
  if (cascade !== prevState.cascade && cascade) {
@@ -1096,9 +1093,9 @@ function (_React$Component) {
1096
1093
  _proto.renderNode = function renderNode(node, layer) {
1097
1094
  var _this10 = this;
1098
1095
 
1099
- var _this$state5 = this.state,
1100
- activeNode = _this$state5.activeNode,
1101
- searchKeyword = _this$state5.searchKeyword;
1096
+ var _this$state4 = this.state,
1097
+ activeNode = _this$state4.activeNode,
1098
+ searchKeyword = _this$state4.searchKeyword;
1102
1099
  var _this$props11 = this.props,
1103
1100
  valueKey = _this$props11.valueKey,
1104
1101
  labelKey = _this$props11.labelKey,
@@ -1166,10 +1163,10 @@ function (_React$Component) {
1166
1163
  };
1167
1164
 
1168
1165
  _proto.renderVirtualNode = function renderVirtualNode(node, options) {
1169
- var _this$state6 = this.state,
1170
- activeNode = _this$state6.activeNode,
1171
- expandAll = _this$state6.expandAll,
1172
- searchKeyword = _this$state6.searchKeyword;
1166
+ var _this$state5 = this.state,
1167
+ activeNode = _this$state5.activeNode,
1168
+ expandAll = _this$state5.expandAll,
1169
+ searchKeyword = _this$state5.searchKeyword;
1173
1170
  var _this$props12 = this.props,
1174
1171
  valueKey = _this$props12.valueKey,
1175
1172
  labelKey = _this$props12.labelKey,
@@ -1219,9 +1216,9 @@ function (_React$Component) {
1219
1216
  _this11 = this,
1220
1217
  _classNames3;
1221
1218
 
1222
- var _this$state7 = this.state,
1223
- filterData = _this$state7.filterData,
1224
- isSomeNodeHasChildren = _this$state7.isSomeNodeHasChildren;
1219
+ var _this$state6 = this.state,
1220
+ filterData = _this$state6.filterData,
1221
+ isSomeNodeHasChildren = _this$state6.isSomeNodeHasChildren;
1225
1222
  var _this$props13 = this.props,
1226
1223
  inline = _this$props13.inline,
1227
1224
  style = _this$props13.style,
@@ -1312,9 +1309,9 @@ function (_React$Component) {
1312
1309
  renderValue = _this$props14.renderValue,
1313
1310
  positionRef = _this$props14.positionRef,
1314
1311
  rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props14, ["cascade", "style", "locale", "inline", "disabled", "valueKey", "labelKey", "cleanable", "countable", "placeholder", "toggleComponentClass", "onExited", "onEntered", "onClean", "renderValue", "positionRef"]);
1315
- var _this$state8 = this.state,
1316
- hasValue = _this$state8.hasValue,
1317
- selectedValues = _this$state8.selectedValues;
1312
+ var _this$state7 = this.state,
1313
+ hasValue = _this$state7.hasValue,
1314
+ selectedValues = _this$state7.selectedValues;
1318
1315
  var hasValidValue = hasValue || selectedValues.length > 0 && (0, _isFunction2.default)(renderValue);
1319
1316
  var selectedItems = this.getSelectedItems(selectedValues);
1320
1317
  var selectedElement = placeholder;
@@ -189,6 +189,17 @@ function (_React$Component) {
189
189
  }
190
190
  };
191
191
 
192
+ _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
193
+ var preValue = prevProps.value;
194
+ var currentValue = this.props.value;
195
+
196
+ if (preValue !== currentValue) {
197
+ this.setState({
198
+ value: currentValue
199
+ });
200
+ }
201
+ };
202
+
192
203
  _proto.getValue = function getValue() {
193
204
  var value = this.props.value;
194
205
  return (0, _isUndefined2.default)(value) ? this.state.value : value;
@@ -69,6 +69,7 @@ function (_React$Component2) {
69
69
  _this.lastFocus = null;
70
70
  _this.onDocumentKeyupListener = null;
71
71
  _this.onFocusinListener = null;
72
+ _this._isMounted = null;
72
73
 
73
74
  _this.setMountNodeRef = function (ref) {
74
75
  var _ref$getMountNode;
@@ -116,15 +117,30 @@ function (_React$Component2) {
116
117
  _this.enforceFocus = function () {
117
118
  var enforceFocus = _this.props.enforceFocus;
118
119
 
119
- if (!enforceFocus || !_this.isTopModal()) {
120
+ if (!enforceFocus || !_this._isMounted || !_this.isTopModal()) {
120
121
  return;
121
122
  }
122
123
 
123
- var active = (0, _domLib.activeElement)((0, _domLib.ownerDocument)((0, _assertThisInitialized2.default)(_this)));
124
+ var currentActiveElement = (0, _domLib.activeElement)((0, _domLib.ownerDocument)((0, _assertThisInitialized2.default)(_this)));
124
125
 
125
126
  var modal = _this.getDialogElement();
126
127
 
127
- if (modal && modal !== active && !(0, _domLib.contains)(modal, active)) {
128
+ if (modal && modal !== currentActiveElement && !(0, _domLib.contains)(modal, currentActiveElement)) {
129
+ modal.focus();
130
+ }
131
+ };
132
+
133
+ _this.handlePortalRendered = function () {
134
+ if (!_this.props.autoFocus) {
135
+ return;
136
+ }
137
+
138
+ var modal = _this.getDialogElement();
139
+
140
+ var currentActiveElement = (0, _domLib.activeElement)((0, _domLib.ownerDocument)((0, _assertThisInitialized2.default)(_this)));
141
+
142
+ if (modal && modal !== currentActiveElement && !(0, _domLib.contains)(modal, currentActiveElement)) {
143
+ _this.lastFocus = currentActiveElement;
128
144
  modal.focus();
129
145
  }
130
146
  };
@@ -141,6 +157,8 @@ function (_React$Component2) {
141
157
  var _proto2 = BaseModal.prototype;
142
158
 
143
159
  _proto2.componentDidMount = function componentDidMount() {
160
+ this._isMounted = true;
161
+
144
162
  if (this.props.show) {
145
163
  this.onShow();
146
164
  }
@@ -184,6 +202,7 @@ function (_React$Component2) {
184
202
  var _this$props4 = this.props,
185
203
  show = _this$props4.show,
186
204
  transition = _this$props4.transition;
205
+ this._isMounted = false;
187
206
 
188
207
  if (show || transition && !this.state.exited) {
189
208
  this.onHide();
@@ -312,7 +331,8 @@ function (_React$Component2) {
312
331
 
313
332
  return React.createElement(_Portal.default, {
314
333
  ref: this.setMountNodeRef,
315
- container: container
334
+ container: container,
335
+ onRendered: this.handlePortalRendered
316
336
  }, React.createElement("div", {
317
337
  ref: this.modalNodeRef,
318
338
  role: rest.role,
@@ -82,6 +82,7 @@ function (_React$Component) {
82
82
  return React.createElement("div", (0, _extends2.default)({}, props, {
83
83
  title: null,
84
84
  role: "dialog",
85
+ tabIndex: -1,
85
86
  ref: (0, _mergeRefs.default)(this.bindHtmlRef, dialogRef),
86
87
  className: (0, _classnames.default)(classPrefix, className),
87
88
  style: modalStyle
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsuite",
3
- "version": "4.10.5",
3
+ "version": "4.10.8",
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
  "prop-types": "^15.7.2",
64
64
  "react-lifecycles-compat": "^3.0.4",
65
65
  "react-virtualized": "^9.21.0",
66
- "rsuite-table": "^3.15.1",
66
+ "rsuite-table": "^3.16.0",
67
67
  "schema-typed": "^1.5.1"
68
68
  },
69
69
  "peerDependencies": {
@@ -112,7 +112,7 @@
112
112
  "css-loader": "^0.28.11",
113
113
  "cssnano": "^4.1.10",
114
114
  "del": "^3.0.0",
115
- "dtslint": "^0.3.0",
115
+ "dtslint": "^4.2.1",
116
116
  "enzyme": "^3.3.0",
117
117
  "enzyme-adapter-react-16": "^1.1.1",
118
118
  "eslint": "^6.7.2",
@@ -234,7 +234,7 @@ class CheckTreePicker extends React.Component<CheckTreePickerProps, CheckTreePic
234
234
  }
235
235
 
236
236
  updateDataChange(prevState: CheckTreePickerState) {
237
- const { searchKeyword, expandItemValues } = this.state;
237
+ const { searchKeyword } = this.state;
238
238
  const { data = [], childrenKey } = this.props;
239
239
 
240
240
  if (prevState.data !== data) {
@@ -242,8 +242,7 @@ class CheckTreePicker extends React.Component<CheckTreePickerProps, CheckTreePic
242
242
  this.nodes = {};
243
243
  this.flattenNodes(nextData);
244
244
  this.unserializeLists({
245
- check: this.getValue(),
246
- expand: expandItemValues
245
+ check: this.getValue()
247
246
  });
248
247
 
249
248
  this.setState({
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import ReactTestUtils from 'react-dom/test-utils';
3
3
  import Enzyme, { mount } from 'enzyme';
4
4
  import Adapter from 'enzyme-adapter-react-16';
@@ -567,4 +567,45 @@ describe('CheckTreePicker', () => {
567
567
  4
568
568
  );
569
569
  });
570
+ it('Should expand when has props defaultExpandAll and data change', () => {
571
+ const Wrapper = React.forwardRef((props, ref) => {
572
+ const nextData = [
573
+ {
574
+ label: 'Fujian',
575
+ value: 3,
576
+ children: [
577
+ {
578
+ label: 'Fuzhou',
579
+ value: 36
580
+ }
581
+ ]
582
+ },
583
+ {
584
+ label: 'Guangdong',
585
+ value: 4,
586
+ children: [
587
+ {
588
+ label: 'Guangzhou',
589
+ value: 45
590
+ }
591
+ ]
592
+ }
593
+ ];
594
+ const [willChangeData, setData] = useState(data);
595
+ const handleClick = () => {
596
+ setData(nextData);
597
+ };
598
+ return (
599
+ <div ref={ref}>
600
+ <button onClick={handleClick} className="change-data">
601
+ change data
602
+ </button>
603
+ <CheckTreePicker inline defaultExpandAll data={willChangeData} />
604
+ </div>
605
+ );
606
+ });
607
+ const instance = getDOMNode(<Wrapper />);
608
+ ReactTestUtils.Simulate.click(instance.querySelector('.change-data'));
609
+ expect(instance.querySelectorAll('.rs-check-tree-open').length).to.equal(2);
610
+ });
570
611
  });
@@ -115,6 +115,15 @@ class InputNumber extends React.Component<InputNumberProps, InputNumberState> {
115
115
  this.inputWheelListener.off();
116
116
  }
117
117
  }
118
+ componentDidUpdate(prevProps: InputNumberProps) {
119
+ const { value: preValue } = prevProps;
120
+ const { value: currentValue } = this.props;
121
+ if (preValue !== currentValue) {
122
+ this.setState({
123
+ value: currentValue
124
+ });
125
+ }
126
+ }
118
127
 
119
128
  bindInputRef = ref => {
120
129
  this.input = ref;
@@ -149,4 +149,29 @@ describe('InputNumber', () => {
149
149
  const instance = getDOMNode(<InputNumber classPrefix="custom-prefix" />);
150
150
  assert.ok(instance.className.match(/\bcustom-prefix\b/));
151
151
  });
152
+ it('should be change correct value when reset value', () => {
153
+ let refValue = 0;
154
+ const Wrapper = React.forwardRef((props, ref) => {
155
+ const [value, setValue] = React.useState(refValue);
156
+ const reset = () => {
157
+ setValue(null);
158
+ };
159
+ refValue = value;
160
+ return (
161
+ <div ref={ref}>
162
+ <InputNumber value={value} onChange={setValue} />
163
+ <button id="reset" onClick={reset}>
164
+ reset
165
+ </button>
166
+ </div>
167
+ );
168
+ });
169
+ const instance = getDOMNode(<Wrapper />);
170
+ const resetBtn = instance.querySelector('#reset');
171
+ ReactTestUtils.Simulate.change(instance.querySelector('.rs-input'), { target: { value: 1 } });
172
+ ReactTestUtils.Simulate.click(resetBtn);
173
+ ReactTestUtils.Simulate.change(instance.querySelector('.rs-input'), { target: { value: 1 } });
174
+
175
+ assert.equal(refValue, 1);
176
+ });
152
177
  });
@@ -50,6 +50,7 @@ class BaseModal extends React.Component<BaseModalProps, BaseModalState> {
50
50
  lastFocus = null;
51
51
  onDocumentKeyupListener = null;
52
52
  onFocusinListener = null;
53
+ _isMounted = null;
53
54
 
54
55
  constructor(props: BaseModalProps) {
55
56
  super(props);
@@ -59,6 +60,7 @@ class BaseModal extends React.Component<BaseModalProps, BaseModalState> {
59
60
  this.dialogRef = React.createRef();
60
61
  }
61
62
  componentDidMount() {
63
+ this._isMounted = true;
62
64
  if (this.props.show) {
63
65
  this.onShow();
64
66
  }
@@ -95,6 +97,8 @@ class BaseModal extends React.Component<BaseModalProps, BaseModalState> {
95
97
  componentWillUnmount() {
96
98
  const { show, transition } = this.props;
97
99
 
100
+ this._isMounted = false;
101
+
98
102
  if (show || (transition && !this.state.exited)) {
99
103
  this.onHide();
100
104
  }
@@ -173,14 +177,28 @@ class BaseModal extends React.Component<BaseModalProps, BaseModalState> {
173
177
  enforceFocus = () => {
174
178
  const { enforceFocus } = this.props;
175
179
 
176
- if (!enforceFocus || !this.isTopModal()) {
180
+ if (!enforceFocus || !this._isMounted || !this.isTopModal()) {
181
+ return;
182
+ }
183
+
184
+ const currentActiveElement = activeElement(ownerDocument(this));
185
+ const modal = this.getDialogElement();
186
+
187
+ if (modal && modal !== currentActiveElement && !contains(modal, currentActiveElement)) {
188
+ modal.focus();
189
+ }
190
+ };
191
+
192
+ handlePortalRendered = () => {
193
+ if (!this.props.autoFocus) {
177
194
  return;
178
195
  }
179
196
 
180
- const active = activeElement(ownerDocument(this));
181
197
  const modal = this.getDialogElement();
198
+ const currentActiveElement = activeElement(ownerDocument(this));
182
199
 
183
- if (modal && modal !== active && !contains(modal, active)) {
200
+ if (modal && modal !== currentActiveElement && !contains(modal, currentActiveElement)) {
201
+ this.lastFocus = currentActiveElement;
184
202
  modal.focus();
185
203
  }
186
204
  };
@@ -268,7 +286,11 @@ class BaseModal extends React.Component<BaseModalProps, BaseModalState> {
268
286
  }
269
287
 
270
288
  return (
271
- <Portal ref={this.setMountNodeRef} container={container}>
289
+ <Portal
290
+ ref={this.setMountNodeRef}
291
+ container={container}
292
+ onRendered={this.handlePortalRendered}
293
+ >
272
294
  <div ref={this.modalNodeRef} role={rest.role} style={style} className={className}>
273
295
  {backdrop && this.renderBackdrop()}
274
296
  <RefHolder ref={this.dialogRef}>{dialog}</RefHolder>
@@ -53,6 +53,7 @@ class ModalDialog extends React.Component<ModalDialogProps> {
53
53
  {...props}
54
54
  title={null}
55
55
  role="dialog"
56
+ tabIndex={-1}
56
57
  ref={mergeRefs(this.bindHtmlRef, dialogRef)}
57
58
  className={classNames(classPrefix, className)}
58
59
  style={modalStyle}
@@ -124,4 +124,9 @@ describe('Modal', () => {
124
124
  const instance = getInstance(<Modal classPrefix="custom-prefix" show />);
125
125
  assert.ok(instance.dialogElement.className.match(/\bcustom-prefix\b/));
126
126
  });
127
+
128
+ it('Should be forced to focus on Modal', () => {
129
+ const instance = getInstance(<Modal className="custom" show />);
130
+ assert.equal(instance.dialogElement, document.activeElement);
131
+ });
127
132
  });