@douyinfe/semi-foundation 2.7.1 → 2.8.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 (37) hide show
  1. package/datePicker/_utils/getDefaultPickerDate.ts +54 -0
  2. package/datePicker/datePicker.scss +2 -2
  3. package/form/form.scss +12 -4
  4. package/inputNumber/foundation.ts +1 -1
  5. package/lib/cjs/datePicker/_utils/getDefaultPickerDate.d.ts +15 -0
  6. package/lib/cjs/datePicker/_utils/getDefaultPickerDate.js +73 -0
  7. package/lib/cjs/datePicker/datePicker.css +14 -14
  8. package/lib/cjs/datePicker/datePicker.scss +2 -2
  9. package/lib/cjs/form/form.css +11 -2
  10. package/lib/cjs/form/form.scss +12 -4
  11. package/lib/cjs/inputNumber/foundation.js +1 -1
  12. package/lib/cjs/tooltip/foundation.d.ts +27 -1
  13. package/lib/cjs/tooltip/foundation.js +159 -3
  14. package/lib/cjs/utils/getHighlight.js +1 -1
  15. package/lib/cjs/utils/isEscPress.d.ts +4 -0
  16. package/lib/cjs/utils/isEscPress.js +22 -0
  17. package/lib/cjs/utils/keyCode.d.ts +1 -0
  18. package/lib/cjs/utils/keyCode.js +3 -1
  19. package/lib/es/datePicker/_utils/getDefaultPickerDate.d.ts +15 -0
  20. package/lib/es/datePicker/_utils/getDefaultPickerDate.js +57 -0
  21. package/lib/es/datePicker/datePicker.css +14 -14
  22. package/lib/es/datePicker/datePicker.scss +2 -2
  23. package/lib/es/form/form.css +11 -2
  24. package/lib/es/form/form.scss +12 -4
  25. package/lib/es/inputNumber/foundation.js +1 -1
  26. package/lib/es/tooltip/foundation.d.ts +27 -1
  27. package/lib/es/tooltip/foundation.js +159 -3
  28. package/lib/es/utils/getHighlight.js +1 -1
  29. package/lib/es/utils/isEscPress.d.ts +4 -0
  30. package/lib/es/utils/isEscPress.js +8 -0
  31. package/lib/es/utils/keyCode.d.ts +1 -0
  32. package/lib/es/utils/keyCode.js +1 -0
  33. package/package.json +3 -3
  34. package/tooltip/foundation.ts +131 -3
  35. package/utils/getHighlight.ts +1 -1
  36. package/utils/isEscPress.ts +8 -0
  37. package/utils/keyCode.ts +1 -0
@@ -0,0 +1,54 @@
1
+ import { addMonths, Locale as dateFnsLocale } from 'date-fns';
2
+ import isValidDate from './isValidDate';
3
+ import { compatiableParse } from './parser';
4
+ import isTimestamp from './isTimestamp';
5
+
6
+ /**
7
+ * get left panel picker date and right panel picker date
8
+ */
9
+ export default function getDefaultPickerDate(options: GetDefaultPickerValueDateOptions) {
10
+ const { defaultPickerValue, format, dateFnsLocale } = options;
11
+ let nowDate = Array.isArray(defaultPickerValue) ? defaultPickerValue[0] : defaultPickerValue;
12
+ let nextDate = Array.isArray(defaultPickerValue) ? defaultPickerValue[1] : undefined;
13
+
14
+ switch (true) {
15
+ case isValidDate(nowDate):
16
+ break;
17
+ case isTimestamp(nowDate):
18
+ nowDate = new Date(nowDate);
19
+ break;
20
+ case typeof nowDate === 'string':
21
+ nowDate = compatiableParse(nowDate as string, format, undefined, dateFnsLocale);
22
+ break;
23
+ default:
24
+ nowDate = new Date();
25
+ break;
26
+ }
27
+
28
+ switch (true) {
29
+ case isValidDate(nextDate):
30
+ break;
31
+ case isTimestamp(nextDate):
32
+ nextDate = new Date(nextDate);
33
+ break;
34
+ case typeof nextDate === 'string':
35
+ nextDate = compatiableParse(nextDate as string, format, undefined, dateFnsLocale);
36
+ break;
37
+ default:
38
+ nextDate = addMonths(nowDate as Date, 1);
39
+ break;
40
+ }
41
+
42
+ return {
43
+ nowDate: nowDate as Date,
44
+ nextDate: nextDate as Date,
45
+ };
46
+ }
47
+
48
+ type BaseValueType = string | number | Date;
49
+
50
+ interface GetDefaultPickerValueDateOptions {
51
+ defaultPickerValue?: BaseValueType | BaseValueType[];
52
+ format: string;
53
+ dateFnsLocale: dateFnsLocale;
54
+ }
@@ -46,7 +46,7 @@ $module: #{$prefix}-datepicker;
46
46
  min-height: $height-datepicker_dateType_yamShowing_min;
47
47
  }
48
48
 
49
- &[x-insetInput=true] {
49
+ &[x-insetinput=true] {
50
50
  .#{$module}-month-grid-left,
51
51
  .#{$module}-month-grid-right {
52
52
  &[x-open-type=year] {
@@ -928,7 +928,7 @@ $module: #{$prefix}-datepicker;
928
928
  }
929
929
  }
930
930
 
931
- &[x-insetInput=true] {
931
+ &[x-insetinput=true] {
932
932
  .#{$module}-month-grid-left,
933
933
  .#{$module}-month-grid-right {
934
934
  &[x-open-type=year] {
package/form/form.scss CHANGED
@@ -91,18 +91,18 @@ $rating: #{$prefix}-rating;
91
91
  }
92
92
 
93
93
  &-with-extra {
94
- .#{$field}-label-text,
95
- .#{$field}-label-extra {
94
+ .#{$field}-label-text {
96
95
  display: inline-block;
97
96
  }
98
97
  .#{$field}-label-extra {
98
+ display: flex;
99
+ align-items: center;
99
100
  margin-left: $spacing-form_label_extra-marginLeft;
100
101
  }
101
102
  }
102
103
 
103
104
  &-required {
104
105
  .#{$field}-label-text {
105
-
106
106
  &::after {
107
107
  content: "*";
108
108
  margin-left: $spacing-form_label_required-marginLeft;
@@ -156,6 +156,11 @@ $rating: #{$prefix}-rating;
156
156
  padding-top: $spacing-form_label_posTop-paddingTop;
157
157
  padding-bottom: $spacing-form_label_posTop-paddingBottom;
158
158
  }
159
+ .#{$field}-label-with-extra {
160
+ display: flex;
161
+ align-items: center;
162
+ }
163
+
159
164
  }
160
165
 
161
166
  &[x-label-pos="left"] {
@@ -168,7 +173,10 @@ $rating: #{$prefix}-rating;
168
173
  padding-top: $spacing-form_label-paddingTop;
169
174
  padding-bottom: $spacing-form_label-paddingTop;
170
175
  }
171
-
176
+ .#{$field}-label-with-extra {
177
+ display: flex;
178
+ align-items: center;
179
+ }
172
180
  .#{$checkboxGroup},
173
181
  .#{$radioGroup} {
174
182
  padding-top: $spacing-form_label-paddingTop;
@@ -432,7 +432,7 @@ class InputNumberFoundation extends BaseFoundation<InputNumberAdapter> {
432
432
 
433
433
  _adjustPrec(num: string | number) {
434
434
  const precision = this.getProp('precision');
435
- if (typeof precision === 'number') {
435
+ if (typeof precision === 'number' && num !== '') {
436
436
  num = Number(num).toFixed(precision);
437
437
  }
438
438
  return toString(num);
@@ -0,0 +1,15 @@
1
+ import { Locale as dateFnsLocale } from 'date-fns';
2
+ /**
3
+ * get left panel picker date and right panel picker date
4
+ */
5
+ export default function getDefaultPickerDate(options: GetDefaultPickerValueDateOptions): {
6
+ nowDate: Date;
7
+ nextDate: Date;
8
+ };
9
+ declare type BaseValueType = string | number | Date;
10
+ interface GetDefaultPickerValueDateOptions {
11
+ defaultPickerValue?: BaseValueType | BaseValueType[];
12
+ format: string;
13
+ dateFnsLocale: dateFnsLocale;
14
+ }
15
+ export {};
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
4
+
5
+ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
6
+
7
+ _Object$defineProperty(exports, "__esModule", {
8
+ value: true
9
+ });
10
+
11
+ exports.default = getDefaultPickerDate;
12
+
13
+ var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
14
+
15
+ var _dateFns = require("date-fns");
16
+
17
+ var _isValidDate = _interopRequireDefault(require("./isValidDate"));
18
+
19
+ var _parser = require("./parser");
20
+
21
+ var _isTimestamp = _interopRequireDefault(require("./isTimestamp"));
22
+
23
+ /**
24
+ * get left panel picker date and right panel picker date
25
+ */
26
+ function getDefaultPickerDate(options) {
27
+ const {
28
+ defaultPickerValue,
29
+ format,
30
+ dateFnsLocale
31
+ } = options;
32
+ let nowDate = (0, _isArray.default)(defaultPickerValue) ? defaultPickerValue[0] : defaultPickerValue;
33
+ let nextDate = (0, _isArray.default)(defaultPickerValue) ? defaultPickerValue[1] : undefined;
34
+
35
+ switch (true) {
36
+ case (0, _isValidDate.default)(nowDate):
37
+ break;
38
+
39
+ case (0, _isTimestamp.default)(nowDate):
40
+ nowDate = new Date(nowDate);
41
+ break;
42
+
43
+ case typeof nowDate === 'string':
44
+ nowDate = (0, _parser.compatiableParse)(nowDate, format, undefined, dateFnsLocale);
45
+ break;
46
+
47
+ default:
48
+ nowDate = new Date();
49
+ break;
50
+ }
51
+
52
+ switch (true) {
53
+ case (0, _isValidDate.default)(nextDate):
54
+ break;
55
+
56
+ case (0, _isTimestamp.default)(nextDate):
57
+ nextDate = new Date(nextDate);
58
+ break;
59
+
60
+ case typeof nextDate === 'string':
61
+ nextDate = (0, _parser.compatiableParse)(nextDate, format, undefined, dateFnsLocale);
62
+ break;
63
+
64
+ default:
65
+ nextDate = (0, _dateFns.addMonths)(nowDate, 1);
66
+ break;
67
+ }
68
+
69
+ return {
70
+ nowDate: nowDate,
71
+ nextDate: nextDate
72
+ };
73
+ }
@@ -30,22 +30,22 @@
30
30
  .semi-datepicker-month-grid[x-type=date] .semi-datepicker-yam-showing {
31
31
  min-height: 325px;
32
32
  }
33
- .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-left[x-open-type=year],
34
- .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-right[x-open-type=year] {
33
+ .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-left[x-open-type=year],
34
+ .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-right[x-open-type=year] {
35
35
  min-height: 312px;
36
36
  }
37
- .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-left[x-open-type=time],
38
- .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-right[x-open-type=time] {
37
+ .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-left[x-open-type=time],
38
+ .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-right[x-open-type=time] {
39
39
  min-height: 314px;
40
40
  }
41
- .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-navigation {
41
+ .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-navigation {
42
42
  padding-top: 8px;
43
43
  padding-bottom: 8px;
44
44
  }
45
- .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-tpk {
45
+ .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-tpk {
46
46
  min-height: 100%;
47
47
  }
48
- .semi-datepicker-month-grid[x-insetInput=true][x-type=dateTime] .semi-datepicker-yam, .semi-datepicker-month-grid[x-insetInput=true][x-type=dateTimeRange] .semi-datepicker-yam {
48
+ .semi-datepicker-month-grid[x-insetinput=true][x-type=dateTime] .semi-datepicker-yam, .semi-datepicker-month-grid[x-insetinput=true][x-type=dateTimeRange] .semi-datepicker-yam {
49
49
  height: 100%;
50
50
  }
51
51
  .semi-datepicker-month-grid .semi-datepicker-yearmonth-header {
@@ -620,21 +620,21 @@
620
620
  .semi-datepicker-compact .semi-datepicker-month-grid[x-panel-yearandmonth-open-type=left] .semi-datepicker-weeks, .semi-datepicker-compact .semi-datepicker-month-grid[x-panel-yearandmonth-open-type=right] .semi-datepicker-weeks {
621
621
  min-height: 168px;
622
622
  }
623
- .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-left[x-open-type=year],
624
- .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-right[x-open-type=year] {
623
+ .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-left[x-open-type=year],
624
+ .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-right[x-open-type=year] {
625
625
  min-height: 236px;
626
626
  }
627
- .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-left[x-open-type=time],
628
- .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-month-grid-right[x-open-type=time] {
627
+ .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-left[x-open-type=time],
628
+ .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-month-grid-right[x-open-type=time] {
629
629
  min-height: 236px;
630
630
  }
631
- .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-yam-showing {
631
+ .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-yam-showing {
632
632
  min-height: 236px;
633
633
  }
634
- .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true] .semi-datepicker-tpk {
634
+ .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true] .semi-datepicker-tpk {
635
635
  min-height: 100%;
636
636
  }
637
- .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true][x-type=dateTime] .semi-datepicker-yam, .semi-datepicker-compact .semi-datepicker-month-grid[x-insetInput=true][x-type=dateTimeRange] .semi-datepicker-yam {
637
+ .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true][x-type=dateTime] .semi-datepicker-yam, .semi-datepicker-compact .semi-datepicker-month-grid[x-insetinput=true][x-type=dateTimeRange] .semi-datepicker-yam {
638
638
  height: 100%;
639
639
  }
640
640
  .semi-datepicker-compact.semi-datepicker-panel-yam .semi-scrolllist {
@@ -46,7 +46,7 @@ $module: #{$prefix}-datepicker;
46
46
  min-height: $height-datepicker_dateType_yamShowing_min;
47
47
  }
48
48
 
49
- &[x-insetInput=true] {
49
+ &[x-insetinput=true] {
50
50
  .#{$module}-month-grid-left,
51
51
  .#{$module}-month-grid-right {
52
52
  &[x-open-type=year] {
@@ -928,7 +928,7 @@ $module: #{$prefix}-datepicker;
928
928
  }
929
929
  }
930
930
 
931
- &[x-insetInput=true] {
931
+ &[x-insetinput=true] {
932
932
  .#{$module}-month-grid-left,
933
933
  .#{$module}-month-grid-right {
934
934
  &[x-open-type=year] {
@@ -52,11 +52,12 @@
52
52
  .semi-form-field-label-disabled {
53
53
  color: var(--semi-color-disabled-text);
54
54
  }
55
- .semi-form-field-label-with-extra .semi-form-field-label-text,
56
- .semi-form-field-label-with-extra .semi-form-field-label-extra {
55
+ .semi-form-field-label-with-extra .semi-form-field-label-text {
57
56
  display: inline-block;
58
57
  }
59
58
  .semi-form-field-label-with-extra .semi-form-field-label-extra {
59
+ display: flex;
60
+ align-items: center;
60
61
  margin-left: 4px;
61
62
  }
62
63
  .semi-form-field-label-required .semi-form-field-label-text::after {
@@ -97,6 +98,10 @@
97
98
  padding-top: 4px;
98
99
  padding-bottom: 4px;
99
100
  }
101
+ .semi-form-field[x-label-pos=top] .semi-form-field-label-with-extra {
102
+ display: flex;
103
+ align-items: center;
104
+ }
100
105
  .semi-form-field[x-label-pos=left] {
101
106
  display: flex;
102
107
  }
@@ -106,6 +111,10 @@
106
111
  padding-top: 6px;
107
112
  padding-bottom: 6px;
108
113
  }
114
+ .semi-form-field[x-label-pos=left] .semi-form-field-label-with-extra {
115
+ display: flex;
116
+ align-items: center;
117
+ }
109
118
  .semi-form-field[x-label-pos=left] .semi-checkboxGroup,
110
119
  .semi-form-field[x-label-pos=left] .semi-radioGroup {
111
120
  padding-top: 6px;
@@ -91,18 +91,18 @@ $rating: #{$prefix}-rating;
91
91
  }
92
92
 
93
93
  &-with-extra {
94
- .#{$field}-label-text,
95
- .#{$field}-label-extra {
94
+ .#{$field}-label-text {
96
95
  display: inline-block;
97
96
  }
98
97
  .#{$field}-label-extra {
98
+ display: flex;
99
+ align-items: center;
99
100
  margin-left: $spacing-form_label_extra-marginLeft;
100
101
  }
101
102
  }
102
103
 
103
104
  &-required {
104
105
  .#{$field}-label-text {
105
-
106
106
  &::after {
107
107
  content: "*";
108
108
  margin-left: $spacing-form_label_required-marginLeft;
@@ -156,6 +156,11 @@ $rating: #{$prefix}-rating;
156
156
  padding-top: $spacing-form_label_posTop-paddingTop;
157
157
  padding-bottom: $spacing-form_label_posTop-paddingBottom;
158
158
  }
159
+ .#{$field}-label-with-extra {
160
+ display: flex;
161
+ align-items: center;
162
+ }
163
+
159
164
  }
160
165
 
161
166
  &[x-label-pos="left"] {
@@ -168,7 +173,10 @@ $rating: #{$prefix}-rating;
168
173
  padding-top: $spacing-form_label-paddingTop;
169
174
  padding-bottom: $spacing-form_label-paddingTop;
170
175
  }
171
-
176
+ .#{$field}-label-with-extra {
177
+ display: flex;
178
+ align-items: center;
179
+ }
172
180
  .#{$checkboxGroup},
173
181
  .#{$radioGroup} {
174
182
  padding-top: $spacing-form_label-paddingTop;
@@ -489,7 +489,7 @@ class InputNumberFoundation extends _foundation.default {
489
489
  _adjustPrec(num) {
490
490
  const precision = this.getProp('precision');
491
491
 
492
- if (typeof precision === 'number') {
492
+ if (typeof precision === 'number' && num !== '') {
493
493
  num = Number(num).toFixed(precision);
494
494
  }
495
495
 
@@ -25,6 +25,7 @@ export interface TooltipAdapter<P = Record<string, any>, S = Record<string, any>
25
25
  click: string;
26
26
  focus: string;
27
27
  blur: string;
28
+ keydown: string;
28
29
  };
29
30
  registerTriggerEvent(...args: any[]): void;
30
31
  getTriggerBounding(...args: any[]): DOMRect;
@@ -40,6 +41,12 @@ export interface TooltipAdapter<P = Record<string, any>, S = Record<string, any>
40
41
  updateContainerPosition(): void;
41
42
  updatePlacementAttr(placement: Position): void;
42
43
  getContainerPosition(): string;
44
+ getFocusableElements(node: any): any[];
45
+ getActiveElement(): any;
46
+ getContainer(): any;
47
+ setInitialFocus(): void;
48
+ notifyEscKeydown(event: any): void;
49
+ getTriggerNode(): any;
43
50
  }
44
51
  export declare type Position = ArrayElement<typeof strings.POSITION_SET>;
45
52
  export interface PopupContainerDOMRect extends DOMRectLikeType {
@@ -63,7 +70,9 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
63
70
  _reversePos(position?: string, isVertical?: boolean): string;
64
71
  clearDelayTimer(): void;
65
72
  _generateEvent(types: ArrayElement<typeof strings.TRIGGER_SET>): {
66
- triggerEventSet: {};
73
+ triggerEventSet: {
74
+ [x: string]: (event: any) => void;
75
+ };
67
76
  portalEventSet: {};
68
77
  };
69
78
  onResize: () => void;
@@ -96,4 +105,21 @@ export default class Tooltip<P = Record<string, any>, S = Record<string, any>> e
96
105
  _bindScrollEvent(): void;
97
106
  _unBindScrollEvent(): void;
98
107
  _initContainerPosition(): void;
108
+ handleContainerKeydown: (event: any) => void;
109
+ _handleTriggerKeydown(event: any): void;
110
+ /**
111
+ * focus trigger
112
+ *
113
+ * when trigger is 'focus' or 'hover', onFocus is bind to show popup
114
+ * if we focus trigger, popup will show again
115
+ *
116
+ * 如果 trigger 是 focus 或者 hover,则它绑定了 onFocus,这里我们如果重新 focus 的话,popup 会再次打开
117
+ * 因此 returnFocusOnClose 只支持 click trigger
118
+ */
119
+ _focusTrigger(): void;
120
+ _handleEscKeyDown(event: any): void;
121
+ _handleContainerTabKeyDown(focusableElements: any[], event: any): void;
122
+ _handleContainerShiftTabKeyDown(focusableElements: any[], event: any): void;
123
+ _handleTriggerArrowDownKeydown(focusableElements: any[], event: any): void;
124
+ _handleTriggerArrowUpKeydown(focusableElements: any[], event: any): void;
99
125
  }
@@ -197,6 +197,42 @@ class Tooltip extends _foundation.default {
197
197
  }
198
198
  };
199
199
 
200
+ this.handleContainerKeydown = event => {
201
+ const {
202
+ guardFocus,
203
+ closeOnEsc
204
+ } = this.getProps();
205
+
206
+ switch (event && event.key) {
207
+ case "Escape":
208
+ closeOnEsc && this._handleEscKeyDown(event);
209
+ break;
210
+
211
+ case "Tab":
212
+ if (guardFocus) {
213
+ const container = this._adapter.getContainer();
214
+
215
+ const focusableElements = this._adapter.getFocusableElements(container);
216
+
217
+ const focusableNum = focusableElements.length;
218
+
219
+ if (focusableNum) {
220
+ // Shift + Tab will move focus backward
221
+ if (event.shiftKey) {
222
+ this._handleContainerShiftTabKeyDown(focusableElements, event);
223
+ } else {
224
+ this._handleContainerTabKeyDown(focusableElements, event);
225
+ }
226
+ }
227
+ }
228
+
229
+ break;
230
+
231
+ default:
232
+ break;
233
+ }
234
+ };
235
+
200
236
  this._timer = null;
201
237
  }
202
238
 
@@ -294,7 +330,12 @@ class Tooltip extends _foundation.default {
294
330
  _generateEvent(types) {
295
331
  const eventNames = this._adapter.getEventName();
296
332
 
297
- const triggerEventSet = {};
333
+ const triggerEventSet = {
334
+ // bind esc keydown on trigger for a11y
335
+ [eventNames.keydown]: event => {
336
+ this._handleTriggerKeydown(event);
337
+ }
338
+ };
298
339
  let portalEventSet = {};
299
340
 
300
341
  switch (types) {
@@ -330,6 +371,15 @@ class Tooltip extends _foundation.default {
330
371
  triggerEventSet[eventNames.mouseLeave] = () => {
331
372
  // console.log(e);
332
373
  this.delayHide(); // this.hide('trigger');
374
+ }; // bind focus to hover trigger for a11y
375
+
376
+
377
+ triggerEventSet[eventNames.focus] = () => {
378
+ this.delayShow();
379
+ };
380
+
381
+ triggerEventSet[eventNames.blur] = () => {
382
+ this.delayHide();
333
383
  };
334
384
 
335
385
  portalEventSet = (0, _assign.default)({}, triggerEventSet);
@@ -353,7 +403,7 @@ class Tooltip extends _foundation.default {
353
403
 
354
404
  case 'custom':
355
405
  // when trigger type is 'custom', no need to bind eventHandler
356
- // show/hide completely depond on props.visible which change by user
406
+ // show/hide completely depend on props.visible which change by user
357
407
  break;
358
408
 
359
409
  default:
@@ -379,7 +429,13 @@ class Tooltip extends _foundation.default {
379
429
  const nowVisible = this.getState('visible');
380
430
 
381
431
  if (nowVisible !== isVisible) {
382
- this._adapter.togglePortalVisible(isVisible, () => this._adapter.notifyVisibleChange(isVisible));
432
+ this._adapter.togglePortalVisible(isVisible, () => {
433
+ if (isVisible) {
434
+ this._adapter.setInitialFocus();
435
+ }
436
+
437
+ this._adapter.notifyVisibleChange(isVisible);
438
+ });
383
439
  }
384
440
  }
385
441
 
@@ -876,6 +932,106 @@ class Tooltip extends _foundation.default {
876
932
  this._adapter.updateContainerPosition();
877
933
  }
878
934
 
935
+ _handleTriggerKeydown(event) {
936
+ const {
937
+ closeOnEsc
938
+ } = this.getProps();
939
+
940
+ const container = this._adapter.getContainer();
941
+
942
+ const focusableElements = this._adapter.getFocusableElements(container);
943
+
944
+ const focusableNum = focusableElements.length;
945
+
946
+ switch (event && event.key) {
947
+ case "Escape":
948
+ closeOnEsc && this._handleEscKeyDown(event);
949
+ break;
950
+
951
+ case "ArrowUp":
952
+ focusableNum && this._handleTriggerArrowUpKeydown(focusableElements, event);
953
+ break;
954
+
955
+ case "ArrowDown":
956
+ focusableNum && this._handleTriggerArrowDownKeydown(focusableElements, event);
957
+ break;
958
+
959
+ default:
960
+ break;
961
+ }
962
+ }
963
+ /**
964
+ * focus trigger
965
+ *
966
+ * when trigger is 'focus' or 'hover', onFocus is bind to show popup
967
+ * if we focus trigger, popup will show again
968
+ *
969
+ * 如果 trigger 是 focus 或者 hover,则它绑定了 onFocus,这里我们如果重新 focus 的话,popup 会再次打开
970
+ * 因此 returnFocusOnClose 只支持 click trigger
971
+ */
972
+
973
+
974
+ _focusTrigger() {
975
+ const {
976
+ trigger,
977
+ returnFocusOnClose
978
+ } = this.getProps();
979
+
980
+ if (returnFocusOnClose && trigger === 'click') {
981
+ const triggerNode = this._adapter.getTriggerNode();
982
+
983
+ if (triggerNode && 'focus' in triggerNode) {
984
+ triggerNode.focus();
985
+ }
986
+ }
987
+ }
988
+
989
+ _handleEscKeyDown(event) {
990
+ const {
991
+ trigger
992
+ } = this.getProps();
993
+
994
+ if (trigger !== 'custom') {
995
+ this.hide();
996
+
997
+ this._focusTrigger();
998
+ }
999
+
1000
+ this._adapter.notifyEscKeydown(event);
1001
+ }
1002
+
1003
+ _handleContainerTabKeyDown(focusableElements, event) {
1004
+ const activeElement = this._adapter.getActiveElement();
1005
+
1006
+ const isLastCurrentFocus = focusableElements[focusableElements.length - 1] === activeElement;
1007
+
1008
+ if (isLastCurrentFocus) {
1009
+ focusableElements[0].focus();
1010
+ event.preventDefault(); // prevent browser default tab move behavior
1011
+ }
1012
+ }
1013
+
1014
+ _handleContainerShiftTabKeyDown(focusableElements, event) {
1015
+ const activeElement = this._adapter.getActiveElement();
1016
+
1017
+ const isFirstCurrentFocus = focusableElements[0] === activeElement;
1018
+
1019
+ if (isFirstCurrentFocus) {
1020
+ focusableElements[focusableElements.length - 1].focus();
1021
+ event.preventDefault(); // prevent browser default tab move behavior
1022
+ }
1023
+ }
1024
+
1025
+ _handleTriggerArrowDownKeydown(focusableElements, event) {
1026
+ focusableElements[0].focus();
1027
+ event.preventDefault(); // prevent browser default scroll behavior
1028
+ }
1029
+
1030
+ _handleTriggerArrowUpKeydown(focusableElements, event) {
1031
+ focusableElements[focusableElements.length - 1].focus();
1032
+ event.preventDefault(); // prevent browser default scroll behavior
1033
+ }
1034
+
879
1035
  }
880
1036
 
881
1037
  exports.default = Tooltip;
@@ -182,7 +182,7 @@ const fillInChunks = _ref3 => {
182
182
 
183
183
  const findAll = _ref4 => {
184
184
  let {
185
- autoEscape,
185
+ autoEscape = true,
186
186
  caseSensitive = false,
187
187
  searchWords,
188
188
  sourceString
@@ -0,0 +1,4 @@
1
+ declare function isEscPress<T extends {
2
+ key: string;
3
+ }>(e: T): boolean;
4
+ export default isEscPress;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
4
+
5
+ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
6
+
7
+ _Object$defineProperty(exports, "__esModule", {
8
+ value: true
9
+ });
10
+
11
+ exports.default = void 0;
12
+
13
+ var _get2 = _interopRequireDefault(require("lodash/get"));
14
+
15
+ var _keyCode = require("./keyCode");
16
+
17
+ function isEscPress(e) {
18
+ return (0, _get2.default)(e, 'key') === _keyCode.ESC_KEY ? true : false;
19
+ }
20
+
21
+ var _default = isEscPress;
22
+ exports.default = _default;