@douyinfe/semi-ui 2.7.0 → 2.8.0-beta.1

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 (48) hide show
  1. package/_base/_story/index.stories.js +2 -6
  2. package/_portal/_story/portal.stories.js +1 -5
  3. package/_utils/hooks/usePrevFocus.ts +1 -0
  4. package/_utils/index.ts +29 -1
  5. package/datePicker/_story/v2/FixDefaultPickerValue.jsx +31 -0
  6. package/datePicker/_story/v2/InsetInput.jsx +1 -1
  7. package/datePicker/_story/v2/index.js +1 -0
  8. package/datePicker/monthsGrid.tsx +3 -13
  9. package/dist/css/semi.css +30 -21
  10. package/dist/css/semi.min.css +1 -1
  11. package/dist/umd/semi-ui.js +608 -284
  12. package/dist/umd/semi-ui.js.map +1 -1
  13. package/dist/umd/semi-ui.min.js +1 -1
  14. package/dist/umd/semi-ui.min.js.map +1 -1
  15. package/input/_story/input.stories.js +10 -1
  16. package/inputNumber/_story/inputNumber.stories.js +4 -0
  17. package/lib/cjs/_utils/hooks/usePrevFocus.js +1 -0
  18. package/lib/cjs/_utils/index.d.ts +3 -1
  19. package/lib/cjs/_utils/index.js +25 -1
  20. package/lib/cjs/datePicker/monthsGrid.js +11 -19
  21. package/lib/cjs/modal/useModal/HookModal.js +2 -0
  22. package/lib/cjs/notification/useNotification/index.js +1 -1
  23. package/lib/cjs/popover/index.d.ts +18 -3
  24. package/lib/cjs/popover/index.js +53 -23
  25. package/lib/cjs/tooltip/index.d.ts +22 -4
  26. package/lib/cjs/tooltip/index.js +65 -27
  27. package/lib/es/_utils/hooks/usePrevFocus.js +2 -0
  28. package/lib/es/_utils/index.d.ts +3 -1
  29. package/lib/es/_utils/index.js +18 -0
  30. package/lib/es/datePicker/monthsGrid.js +11 -19
  31. package/lib/es/modal/useModal/HookModal.js +2 -0
  32. package/lib/es/notification/useNotification/index.js +2 -1
  33. package/lib/es/popover/index.d.ts +18 -3
  34. package/lib/es/popover/index.js +52 -23
  35. package/lib/es/tooltip/index.d.ts +22 -4
  36. package/lib/es/tooltip/index.js +65 -27
  37. package/modal/_story/modal.stories.js +93 -1
  38. package/modal/useModal/HookModal.tsx +1 -0
  39. package/notification/_story/useNotification/index.jsx +21 -7
  40. package/notification/useNotification/index.tsx +1 -1
  41. package/package.json +9 -9
  42. package/popover/_story/popover.stories.js +75 -1
  43. package/popover/index.tsx +24 -8
  44. package/select/__test__/select.test.js +16 -0
  45. package/table/_story/v2/FixedMemoryLeak/index.jsx +33 -0
  46. package/table/_story/v2/index.js +2 -1
  47. package/toast/_story/toast.stories.js +41 -0
  48. package/tooltip/index.tsx +72 -22
@@ -6,6 +6,7 @@ import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys";
6
6
  import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
7
7
  import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign";
8
8
  import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
9
+ import _Array$from from "@babel/runtime-corejs3/core-js-stable/array/from";
9
10
 
10
11
  /* eslint-disable max-len */
11
12
 
@@ -13,6 +14,7 @@ import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance
13
14
  import React from 'react';
14
15
  import warning from '@douyinfe/semi-foundation/lib/es/utils/warning';
15
16
  import { findAll } from '@douyinfe/semi-foundation/lib/es/utils/getHighlight';
17
+ import { isHTMLElement } from '@douyinfe/semi-foundation/lib/es/utils/dom';
16
18
  /**
17
19
  * stop propagation
18
20
  *
@@ -168,4 +170,20 @@ export const registerMediaQuery = (media, _ref2) => {
168
170
  export const isSemiIcon = icon => /*#__PURE__*/React.isValidElement(icon) && _get(icon.type, 'elementType') === 'Icon';
169
171
  export function getActiveElement() {
170
172
  return document ? document.activeElement : null;
173
+ }
174
+ export function isNodeContainsFocus(node) {
175
+ const activeElement = getActiveElement();
176
+ return activeElement === node || node.contains(activeElement);
177
+ }
178
+ export function getFocusableElements(node) {
179
+ if (!isHTMLElement(node)) {
180
+ return [];
181
+ }
182
+
183
+ const focusableSelectorsList = ["input:not([disabled]):not([tabindex='-1'])", "textarea:not([disabled]):not([tabindex='-1'])", "button:not([disabled]):not([tabindex='-1'])", "a[href]:not([tabindex='-1'])", "select:not([disabled]):not([tabindex='-1'])", "area[href]:not([tabindex='-1'])", "iframe:not([tabindex='-1'])", "object:not([tabindex='-1'])", "*[tabindex]:not([tabindex='-1'])", "*[contenteditable]:not([tabindex='-1'])"];
184
+ const focusableSelectorsStr = focusableSelectorsList.join(','); // we are not filtered elements which are invisible
185
+
186
+ const focusableElements = _Array$from(node.querySelectorAll(focusableSelectorsStr));
187
+
188
+ return focusableElements;
171
189
  }
@@ -1,7 +1,6 @@
1
1
  import _stubFalse from "lodash/stubFalse";
2
2
  import _noop from "lodash/noop";
3
3
  import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
4
- import _Array$isArray from "@babel/runtime-corejs3/core-js-stable/array/is-array";
5
4
  import _Set from "@babel/runtime-corejs3/core-js-stable/set";
6
5
  import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign";
7
6
  import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
@@ -19,7 +18,7 @@ import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/ins
19
18
  import React from 'react';
20
19
  import classnames from 'classnames';
21
20
  import PropTypes from 'prop-types';
22
- import { format as formatFn, addMonths, isSameDay } from 'date-fns';
21
+ import { format as formatFn, isSameDay } from 'date-fns';
23
22
  import MonthsGridFoundation from '@douyinfe/semi-foundation/lib/es/datePicker/monthsGridFoundation';
24
23
  import { strings, numbers, cssClasses } from '@douyinfe/semi-foundation/lib/es/datePicker/constants';
25
24
  import { compatiableParse } from '@douyinfe/semi-foundation/lib/es/datePicker/_utils/parser';
@@ -30,6 +29,7 @@ import Combobox from '../timePicker/Combobox';
30
29
  import YearAndMonth from './yearAndMonth';
31
30
  import { IconClock, IconCalendar } from '@douyinfe/semi-icons';
32
31
  import { getDefaultFormatTokenByType } from '@douyinfe/semi-foundation/lib/es/datePicker/_utils/getDefaultFormatToken';
32
+ import getDefaultPickerDate from '@douyinfe/semi-foundation/lib/es/datePicker/_utils/getDefaultPickerDate';
33
33
  const prefixCls = cssClasses.PREFIX;
34
34
  export default class MonthsGrid extends BaseComponent {
35
35
  constructor(props) {
@@ -132,23 +132,15 @@ export default class MonthsGrid extends BaseComponent {
132
132
  return this.foundation.getYAMOpenType();
133
133
  };
134
134
 
135
- let nowDate = _Array$isArray(props.defaultPickerValue) ? props.defaultPickerValue[0] : props.defaultPickerValue;
136
135
  const validFormat = props.format || getDefaultFormatTokenByType(props.type);
137
-
138
- if (!nowDate) {
139
- nowDate = new Date();
140
- } else {
141
- nowDate = compatiableParse(nowDate, validFormat, undefined, props.dateFnsLocale);
142
- }
143
-
144
- let nextDate = _Array$isArray(props.defaultPickerValue) ? props.defaultPickerValue[1] : undefined;
145
-
146
- if (!nextDate) {
147
- nextDate = addMonths(nowDate, 1);
148
- } else {
149
- nextDate = compatiableParse(nextDate, validFormat, undefined, props.dateFnsLocale);
150
- }
151
-
136
+ const {
137
+ nowDate,
138
+ nextDate
139
+ } = getDefaultPickerDate({
140
+ defaultPickerValue: props.defaultPickerValue,
141
+ format: validFormat,
142
+ dateFnsLocale: props.dateFnsLocale
143
+ });
152
144
  const dateState = {
153
145
  // Direct use of full date string storage, mainly considering the month rendering comparison to save a conversion
154
146
  // The selected value for single or multiple selection, full date string, eg. {'2019-10-01', '2019-10-02'}
@@ -647,7 +639,7 @@ export default class MonthsGrid extends BaseComponent {
647
639
  className: monthGridCls,
648
640
  "x-type": type,
649
641
  "x-panel-yearandmonth-open-type": yearOpenType,
650
- "x-insetInput": insetInput ? "true" : "false",
642
+ "x-insetinput": insetInput ? "true" : "false",
651
643
  ref: current => this.cacheRefCurrent('monthGrid', current)
652
644
  }, content);
653
645
  }
@@ -39,6 +39,8 @@ const HookModal = (_a, ref) => {
39
39
  const {
40
40
  motion
41
41
  } = props;
42
+ /* istanbul ignore next */
43
+
42
44
  const mergedMotion = typeof motion === 'undefined' || motion ? _Object$assign(_Object$assign({}, motion), {
43
45
  didLeave: function () {
44
46
  const didLeave = _get(props.motion, 'didLeave');
@@ -80,9 +80,10 @@ function usePatchElement() {
80
80
  export default function useNotification() {
81
81
  const [elements, patchElement] = usePatchElement();
82
82
  const noticeRef = new _Map();
83
- const id = getUuid('semi_notice_');
84
83
 
85
84
  const addNotice = config => {
85
+ const id = getUuid('semi_notice_');
86
+
86
87
  const mergeConfig = _Object$assign(_Object$assign({}, config), {
87
88
  id
88
89
  }); // eslint-disable-next-line prefer-const
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { ArrowBounding, Position, Trigger } from '../tooltip/index';
3
+ import { ArrowBounding, Position, TooltipProps, Trigger, RenderContentProps } from '../tooltip/index';
4
4
  import '@douyinfe/semi-foundation/lib/es/popover/popover.css';
5
5
  import { BaseProps } from '../_base/baseComponent';
6
6
  import { Motion } from '../_base/base';
@@ -12,7 +12,7 @@ declare interface ArrowStyle {
12
12
  }
13
13
  export interface PopoverProps extends BaseProps {
14
14
  children?: React.ReactNode;
15
- content?: React.ReactNode;
15
+ content?: TooltipProps['content'];
16
16
  visible?: boolean;
17
17
  autoAdjustOverflow?: boolean;
18
18
  motion?: Motion;
@@ -33,6 +33,10 @@ export interface PopoverProps extends BaseProps {
33
33
  rePosKey?: string | number;
34
34
  getPopupContainer?: () => HTMLElement;
35
35
  zIndex?: number;
36
+ closeOnEsc?: TooltipProps['closeOnEsc'];
37
+ guardFocus?: TooltipProps['guardFocus'];
38
+ returnFocusOnClose?: TooltipProps['returnFocusOnClose'];
39
+ onEscKeyDown?: TooltipProps['onEscKeyDown'];
36
40
  }
37
41
  export interface PopoverState {
38
42
  popConfirmVisible: boolean;
@@ -64,6 +68,7 @@ declare class Popover extends React.PureComponent<PopoverProps, PopoverState> {
64
68
  arrowPointAtCenter: PropTypes.Requireable<boolean>;
65
69
  arrowBounding: PropTypes.Requireable<object>;
66
70
  prefixCls: PropTypes.Requireable<string>;
71
+ guardFocus: PropTypes.Requireable<boolean>;
67
72
  };
68
73
  static defaultProps: {
69
74
  arrowBounding: {
@@ -82,8 +87,18 @@ declare class Popover extends React.PureComponent<PopoverProps, PopoverState> {
82
87
  position: string;
83
88
  prefixCls: string;
84
89
  onClickOutSide: (...args: any[]) => void;
90
+ onEscKeyDown: (...args: any[]) => void;
91
+ closeOnEsc: boolean;
92
+ returnFocusOnClose: boolean;
93
+ guardFocus: boolean;
85
94
  };
86
- renderPopCard(): JSX.Element;
95
+ renderPopCard: ({ initialFocusRef }: {
96
+ initialFocusRef: RenderContentProps['initialFocusRef'];
97
+ }) => JSX.Element;
98
+ renderContentNode: (props: {
99
+ content: TooltipProps['content'];
100
+ initialFocusRef: RenderContentProps['initialFocusRef'];
101
+ }) => React.ReactNode;
87
102
  render(): JSX.Element;
88
103
  }
89
104
  export default Popover;
@@ -1,4 +1,5 @@
1
1
  import _noop from "lodash/noop";
2
+ import _isFunction from "lodash/isFunction";
2
3
  import _indexOfInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/index-of";
3
4
  import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols";
4
5
  import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign";
@@ -26,23 +27,45 @@ const positionSet = strings.POSITION_SET;
26
27
  const triggerSet = strings.TRIGGER_SET;
27
28
 
28
29
  class Popover extends React.PureComponent {
29
- renderPopCard() {
30
- const {
31
- content,
32
- contentClassName,
33
- prefixCls
34
- } = this.props;
35
- const {
36
- direction
37
- } = this.context;
38
- const popCardCls = classNames(prefixCls, contentClassName, {
39
- ["".concat(prefixCls, "-rtl")]: direction === 'rtl'
40
- });
41
- return /*#__PURE__*/React.createElement("div", {
42
- className: popCardCls
43
- }, /*#__PURE__*/React.createElement("div", {
44
- className: "".concat(prefixCls, "-content")
45
- }, content));
30
+ constructor() {
31
+ super(...arguments);
32
+
33
+ this.renderPopCard = _ref => {
34
+ let {
35
+ initialFocusRef
36
+ } = _ref;
37
+ const {
38
+ content,
39
+ contentClassName,
40
+ prefixCls
41
+ } = this.props;
42
+ const {
43
+ direction
44
+ } = this.context;
45
+ const popCardCls = classNames(prefixCls, contentClassName, {
46
+ ["".concat(prefixCls, "-rtl")]: direction === 'rtl'
47
+ });
48
+ const contentNode = this.renderContentNode({
49
+ initialFocusRef,
50
+ content
51
+ });
52
+ return /*#__PURE__*/React.createElement("div", {
53
+ className: popCardCls
54
+ }, /*#__PURE__*/React.createElement("div", {
55
+ className: "".concat(prefixCls, "-content")
56
+ }, contentNode));
57
+ };
58
+
59
+ this.renderContentNode = props => {
60
+ const {
61
+ initialFocusRef,
62
+ content
63
+ } = props;
64
+ const contentProps = {
65
+ initialFocusRef
66
+ };
67
+ return !_isFunction(content) ? content : content(contentProps);
68
+ };
46
69
  }
47
70
 
48
71
  render() {
@@ -62,7 +85,6 @@ class Popover extends React.PureComponent {
62
85
  let {
63
86
  spacing
64
87
  } = this.props;
65
- const popContent = this.renderPopCard();
66
88
  const arrowProps = {
67
89
  position,
68
90
  className: '',
@@ -76,11 +98,13 @@ class Popover extends React.PureComponent {
76
98
  }
77
99
 
78
100
  const role = trigger === 'click' || trigger === 'custom' ? 'dialog' : 'tooltip';
79
- return /*#__PURE__*/React.createElement(Tooltip, _Object$assign({}, attr, {
101
+ return /*#__PURE__*/React.createElement(Tooltip, _Object$assign({
102
+ guardFocus: true
103
+ }, attr, {
80
104
  trigger: trigger,
81
105
  position: position,
82
106
  style: style,
83
- content: popContent,
107
+ content: this.renderPopCard,
84
108
  prefixCls: prefixCls,
85
109
  spacing: spacing,
86
110
  showArrow: arrow,
@@ -94,7 +118,7 @@ class Popover extends React.PureComponent {
94
118
  Popover.contextType = ConfigContext;
95
119
  Popover.propTypes = {
96
120
  children: PropTypes.node,
97
- content: PropTypes.node,
121
+ content: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
98
122
  visible: PropTypes.bool,
99
123
  autoAdjustOverflow: PropTypes.bool,
100
124
  motion: PropTypes.oneOfType([PropTypes.bool, PropTypes.object, PropTypes.func]),
@@ -117,7 +141,8 @@ Popover.propTypes = {
117
141
  }),
118
142
  arrowPointAtCenter: PropTypes.bool,
119
143
  arrowBounding: PropTypes.object,
120
- prefixCls: PropTypes.string
144
+ prefixCls: PropTypes.string,
145
+ guardFocus: PropTypes.bool
121
146
  };
122
147
  Popover.defaultProps = {
123
148
  arrowBounding: numbers.ARROW_BOUNDING,
@@ -130,6 +155,10 @@ Popover.defaultProps = {
130
155
  okText: 'Yes',
131
156
  position: 'bottom',
132
157
  prefixCls: cssClasses.PREFIX,
133
- onClickOutSide: _noop
158
+ onClickOutSide: _noop,
159
+ onEscKeyDown: _noop,
160
+ closeOnEsc: true,
161
+ returnFocusOnClose: true,
162
+ guardFocus: true
134
163
  };
135
164
  export default Popover;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import Event from '@douyinfe/semi-foundation/lib/es/utils/Event';
4
4
  import { ArrayElement } from '@douyinfe/semi-foundation/lib/es/utils/type';
5
- import { TooltipAdapter, Position } from '@douyinfe/semi-foundation/lib/es/tooltip/foundation';
5
+ import TooltipFoundation, { TooltipAdapter, Position } from '@douyinfe/semi-foundation/lib/es/tooltip/foundation';
6
6
  import { strings } from '@douyinfe/semi-foundation/lib/es/tooltip/constants';
7
7
  import '@douyinfe/semi-foundation/lib/es/tooltip/tooltip.css';
8
8
  import BaseComponent, { BaseProps } from '../_base/baseComponent';
@@ -15,6 +15,10 @@ export interface ArrowBounding {
15
15
  width?: number;
16
16
  height?: number;
17
17
  }
18
+ export interface RenderContentProps {
19
+ initialFocusRef?: React.RefObject<HTMLElement>;
20
+ }
21
+ export declare type RenderContent = (props: RenderContentProps) => React.ReactNode;
18
22
  export interface TooltipProps extends BaseProps {
19
23
  children?: React.ReactNode;
20
24
  motion?: Motion;
@@ -28,7 +32,7 @@ export interface TooltipProps extends BaseProps {
28
32
  clickToHide?: boolean;
29
33
  visible?: boolean;
30
34
  style?: React.CSSProperties;
31
- content?: React.ReactNode;
35
+ content?: React.ReactNode | RenderContent;
32
36
  prefixCls?: string;
33
37
  onVisibleChange?: (visible: boolean) => void;
34
38
  onClickOutSide?: (e: React.MouseEvent) => void;
@@ -44,6 +48,10 @@ export interface TooltipProps extends BaseProps {
44
48
  stopPropagation?: boolean;
45
49
  clickTriggerToHide?: boolean;
46
50
  wrapperClassName?: string;
51
+ closeOnEsc?: boolean;
52
+ guardFocus?: boolean;
53
+ returnFocusOnClose?: boolean;
54
+ onEscKeyDown?: (e: React.KeyboardEvent) => void;
47
55
  }
48
56
  interface TooltipState {
49
57
  visible: boolean;
@@ -97,6 +105,8 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
97
105
  stopPropagation: PropTypes.Requireable<boolean>;
98
106
  role: PropTypes.Requireable<string>;
99
107
  wrapWhenSpecial: PropTypes.Requireable<boolean>;
108
+ guardFocus: PropTypes.Requireable<boolean>;
109
+ returnFocusOnClose: PropTypes.Requireable<boolean>;
100
110
  };
101
111
  static defaultProps: {
102
112
  arrowBounding: {
@@ -121,10 +131,15 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
121
131
  showArrow: boolean;
122
132
  wrapWhenSpecial: boolean;
123
133
  zIndex: 1060;
134
+ closeOnEsc: boolean;
135
+ guardFocus: boolean;
136
+ returnFocusOnClose: boolean;
137
+ onEscKeyDown: (...args: any[]) => void;
124
138
  };
125
139
  eventManager: Event;
126
140
  triggerEl: React.RefObject<unknown>;
127
- containerEl: React.RefObject<unknown>;
141
+ containerEl: React.RefObject<HTMLDivElement>;
142
+ initialFocusRef: React.RefObject<HTMLElement>;
128
143
  clickOutsideHandler: any;
129
144
  resizeHandler: any;
130
145
  isWrapped: boolean;
@@ -132,6 +147,7 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
132
147
  scrollHandler: any;
133
148
  getPopupContainer: () => HTMLElement;
134
149
  containerPosition: string;
150
+ foundation: TooltipFoundation;
135
151
  constructor(props: TooltipProps);
136
152
  setContainerEl: (node: HTMLDivElement) => {
137
153
  current: HTMLDivElement;
@@ -142,10 +158,12 @@ export default class Tooltip extends BaseComponent<TooltipProps, TooltipState> {
142
158
  isSpecial: (elem: React.ReactNode | HTMLElement | any) => boolean | "disabled" | "loading";
143
159
  didLeave: () => void;
144
160
  /** for transition - end */
145
- rePosition(): any;
161
+ rePosition(): Record<string, string | number>;
146
162
  componentDidUpdate(prevProps: TooltipProps, prevState: TooltipState): void;
147
163
  renderIcon: () => any;
148
164
  handlePortalInnerClick: (e: React.MouseEvent) => void;
165
+ handlePortalInnerKeyDown: (e: React.KeyboardEvent) => void;
166
+ renderContentNode: (content: TooltipProps['content']) => React.ReactNode;
149
167
  renderPortal: () => JSX.Element;
150
168
  wrapSpan: (elem: React.ReactNode | React.ReactElement) => JSX.Element;
151
169
  mergeEvents: (rawEvents: Record<string, any>, events: Record<string, any>) => {};
@@ -1,3 +1,4 @@
1
+ import _isFunction from "lodash/isFunction";
1
2
  import _isEmpty from "lodash/isEmpty";
2
3
  import _each from "lodash/each";
3
4
  import _omit from "lodash/omit";
@@ -37,7 +38,7 @@ import { getUuidShort } from '@douyinfe/semi-foundation/lib/es/utils/uuid';
37
38
  import '@douyinfe/semi-foundation/lib/es/tooltip/tooltip.css';
38
39
  import BaseComponent from '../_base/baseComponent';
39
40
  import { isHTMLElement } from '../_base/reactUtils';
40
- import { stopPropagation } from '../_utils';
41
+ import { getActiveElement, getFocusableElements, stopPropagation } from '../_utils';
41
42
  import Portal from '../_portal/index';
42
43
  import ConfigContext from '../configProvider/context';
43
44
  import TriangleArrow from './TriangleArrow';
@@ -137,6 +138,17 @@ export default class Tooltip extends BaseComponent {
137
138
  }
138
139
  };
139
140
 
141
+ this.handlePortalInnerKeyDown = e => {
142
+ this.foundation.handleContainerKeydown(e);
143
+ };
144
+
145
+ this.renderContentNode = content => {
146
+ const contentProps = {
147
+ initialFocusRef: this.initialFocusRef
148
+ };
149
+ return !_isFunction(content) ? content : content(contentProps);
150
+ };
151
+
140
152
  this.renderPortal = () => {
141
153
  const {
142
154
  containerStyle = {},
@@ -156,6 +168,7 @@ export default class Tooltip extends BaseComponent {
156
168
  role,
157
169
  zIndex
158
170
  } = this.props;
171
+ const contentNode = this.renderContentNode(content);
159
172
  const {
160
173
  className: propClassName
161
174
  } = this.props;
@@ -193,7 +206,7 @@ export default class Tooltip extends BaseComponent {
193
206
  role: role,
194
207
  "x-placement": placement,
195
208
  id: id
196
- }), content, icon);
209
+ }), contentNode, icon);
197
210
  } : null) : /*#__PURE__*/React.createElement("div", _Object$assign({
198
211
  className: className
199
212
  }, portalEventSet, {
@@ -201,7 +214,7 @@ export default class Tooltip extends BaseComponent {
201
214
  style: _Object$assign({
202
215
  visibility: motion ? undefined : 'visible'
203
216
  }, style)
204
- }), content, icon);
217
+ }), contentNode, icon);
205
218
  return /*#__PURE__*/React.createElement(Portal, {
206
219
  getPopupContainer: this.props.getPopupContainer,
207
220
  style: {
@@ -211,7 +224,8 @@ export default class Tooltip extends BaseComponent {
211
224
  className: "".concat(BASE_CLASS_PREFIX, "-portal-inner"),
212
225
  style: portalInnerStyle,
213
226
  ref: this.setContainerEl,
214
- onClick: this.handlePortalInnerClick
227
+ onClick: this.handlePortalInnerClick,
228
+ onKeyDown: this.handlePortalInnerKeyDown
215
229
  }, inner));
216
230
  };
217
231
 
@@ -279,6 +293,7 @@ export default class Tooltip extends BaseComponent {
279
293
  this.eventManager = new Event();
280
294
  this.triggerEl = /*#__PURE__*/React.createRef();
281
295
  this.containerEl = /*#__PURE__*/React.createRef();
296
+ this.initialFocusRef = /*#__PURE__*/React.createRef();
282
297
  this.clickOutsideHandler = null;
283
298
  this.resizeHandler = null;
284
299
  this.isWrapped = false; // Identifies whether a span element is wrapped
@@ -330,7 +345,8 @@ export default class Tooltip extends BaseComponent {
330
345
  mouseOver: 'onMouseOver',
331
346
  click: 'onClick',
332
347
  focus: 'onFocus',
333
- blur: 'onBlur'
348
+ blur: 'onBlur',
349
+ keydown: 'onKeyDown'
334
350
  }),
335
351
  registerTriggerEvent: triggerEventSet => {
336
352
  this.setState({
@@ -348,14 +364,8 @@ export default class Tooltip extends BaseComponent {
348
364
  // eslint-disable-next-line
349
365
  // It may be a React component or an html element
350
366
  // There is no guarantee that triggerE l.current can get the real dom, so call findDOMNode to ensure that you can get the real dom
351
- let triggerDOM = this.triggerEl.current;
352
-
353
- if (!isHTMLElement(this.triggerEl.current)) {
354
- const realDomNode = ReactDOM.findDOMNode(this.triggerEl.current);
355
- this.triggerEl.current = realDomNode;
356
- triggerDOM = realDomNode;
357
- }
358
-
367
+ const triggerDOM = this.adapter.getTriggerNode();
368
+ this.triggerEl.current = triggerDOM;
359
369
  return triggerDOM && triggerDOM.getBoundingClientRect();
360
370
  },
361
371
  // Gets the outer size of the specified container
@@ -422,7 +432,7 @@ export default class Tooltip extends BaseComponent {
422
432
  willUpdateStates.visible = visible;
423
433
  }
424
434
 
425
- this.setState(willUpdateStates, () => {
435
+ this.mounted && this.setState(willUpdateStates, () => {
426
436
  cb();
427
437
  });
428
438
  },
@@ -492,12 +502,7 @@ export default class Tooltip extends BaseComponent {
492
502
  return false;
493
503
  }
494
504
 
495
- let triggerDOM = this.triggerEl.current;
496
-
497
- if (!isHTMLElement(this.triggerEl.current)) {
498
- triggerDOM = ReactDOM.findDOMNode(this.triggerEl.current);
499
- }
500
-
505
+ const triggerDOM = this.adapter.getTriggerNode();
501
506
  const isRelativeScroll = e.target.contains(triggerDOM);
502
507
 
503
508
  if (isRelativeScroll) {
@@ -528,7 +533,33 @@ export default class Tooltip extends BaseComponent {
528
533
  this.containerPosition = position;
529
534
  }
530
535
  },
531
- getContainerPosition: () => this.containerPosition
536
+ getContainerPosition: () => this.containerPosition,
537
+ getContainer: () => this.containerEl && this.containerEl.current,
538
+ getTriggerNode: () => {
539
+ let triggerDOM = this.triggerEl.current;
540
+
541
+ if (!isHTMLElement(this.triggerEl.current)) {
542
+ triggerDOM = ReactDOM.findDOMNode(this.triggerEl.current);
543
+ }
544
+
545
+ return triggerDOM;
546
+ },
547
+ getFocusableElements: node => {
548
+ return getFocusableElements(node);
549
+ },
550
+ getActiveElement: () => {
551
+ return getActiveElement();
552
+ },
553
+ setInitialFocus: () => {
554
+ const focusRefNode = _get(this, 'initialFocusRef.current');
555
+
556
+ if (focusRefNode && 'focus' in focusRefNode) {
557
+ focusRefNode.focus();
558
+ }
559
+ },
560
+ notifyEscKeydown: event => {
561
+ this.props.onEscKeyDown(event);
562
+ }
532
563
  });
533
564
  }
534
565
 
@@ -570,7 +601,8 @@ export default class Tooltip extends BaseComponent {
570
601
  } = this.state;
571
602
  const {
572
603
  wrapWhenSpecial,
573
- role
604
+ role,
605
+ trigger
574
606
  } = this.props;
575
607
  let {
576
608
  children
@@ -630,7 +662,8 @@ export default class Tooltip extends BaseComponent {
630
662
  } else if (ref && typeof ref === 'object') {
631
663
  ref.current = node;
632
664
  }
633
- }
665
+ },
666
+ tabIndex: trigger === 'hover' ? 0 : undefined
634
667
  })); // If you do not add a layer of div, in order to bind the events and className in the tooltip, you need to cloneElement children, but this time it may overwrite the children's original ref reference
635
668
  // So if the user adds ref to the content, you need to use callback ref: https://github.com/facebook/react/issues/8873
636
669
 
@@ -655,7 +688,7 @@ Tooltip.propTypes = {
655
688
  clickTriggerToHide: PropTypes.bool,
656
689
  visible: PropTypes.bool,
657
690
  style: PropTypes.object,
658
- content: PropTypes.node,
691
+ content: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
659
692
  prefixCls: PropTypes.string,
660
693
  onVisibleChange: PropTypes.func,
661
694
  onClickOutSide: PropTypes.func,
@@ -669,8 +702,9 @@ Tooltip.propTypes = {
669
702
  stopPropagation: PropTypes.bool,
670
703
  // private
671
704
  role: PropTypes.string,
672
- wrapWhenSpecial: PropTypes.bool // when trigger has special status such as "disabled" or "loading", wrap span
673
-
705
+ wrapWhenSpecial: PropTypes.bool,
706
+ guardFocus: PropTypes.bool,
707
+ returnFocusOnClose: PropTypes.bool
674
708
  };
675
709
  Tooltip.defaultProps = {
676
710
  arrowBounding: numbers.ARROW_BOUNDING,
@@ -689,5 +723,9 @@ Tooltip.defaultProps = {
689
723
  spacing: numbers.SPACING,
690
724
  showArrow: true,
691
725
  wrapWhenSpecial: true,
692
- zIndex: numbers.DEFAULT_Z_INDEX
726
+ zIndex: numbers.DEFAULT_Z_INDEX,
727
+ closeOnEsc: false,
728
+ guardFocus: false,
729
+ returnFocusOnClose: false,
730
+ onEscKeyDown: _noop
693
731
  };