@atlaskit/tooltip 17.8.10 → 18.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/tooltip
2
2
 
3
+ ## 18.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#61952](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/61952) [`d00b9272c88c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/d00b9272c88c) - [ux] Tooltips are now hidden during drags. This is to prevent janky UX.
8
+
9
+ ## 18.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - [#41881](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/41881) [`1de74609c13`](https://bitbucket.org/atlassian/atlassian-frontend/commits/1de74609c13) - Removed all remaining legacy theming logic from the Tag, Toggle and Tooltip components.
14
+
3
15
  ## 17.8.10
4
16
 
5
17
  ### Patch Changes
@@ -20,6 +20,7 @@ var _durations = require("@atlaskit/motion/durations");
20
20
  var _popper = require("@atlaskit/popper");
21
21
  var _portal = _interopRequireDefault(require("@atlaskit/portal"));
22
22
  var _constants = require("@atlaskit/theme/constants");
23
+ var _dragManager = require("./internal/drag-manager");
23
24
  var _tooltipManager = require("./internal/tooltip-manager");
24
25
  var _useUniqueId = _interopRequireDefault(require("./internal/use-unique-id"));
25
26
  var _TooltipContainer = _interopRequireDefault(require("./TooltipContainer"));
@@ -32,7 +33,7 @@ var tooltipZIndex = _constants.layers.tooltip();
32
33
  var analyticsAttributes = {
33
34
  componentName: 'tooltip',
34
35
  packageName: "@atlaskit/tooltip",
35
- packageVersion: "17.8.10"
36
+ packageVersion: "18.1.0"
36
37
  };
37
38
 
38
39
  // Inverts motion direction
@@ -165,7 +166,38 @@ function Tooltip(_ref) {
165
166
  }
166
167
  };
167
168
  }, [abort]);
169
+ var isDraggingRef = (0, _react.useRef)(false);
170
+ (0, _react.useEffect)(function () {
171
+ return (0, _dragManager.register)({
172
+ onRegister: function onRegister(_ref2) {
173
+ var isDragging = _ref2.isDragging;
174
+ isDraggingRef.current = isDragging;
175
+ },
176
+ onDragStart: function onDragStart() {
177
+ var _apiRef$current;
178
+ /**
179
+ * Hiding any visible tooltips when a drag starts because otherwise it
180
+ * looks janky (disappears and reappears), and is not required.
181
+ */
182
+ (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || _apiRef$current.requestHide({
183
+ isImmediate: true
184
+ });
185
+ isDraggingRef.current = true;
186
+ },
187
+ onDragEnd: function onDragEnd() {
188
+ isDraggingRef.current = false;
189
+ }
190
+ });
191
+ }, []);
168
192
  var showTooltip = (0, _react.useCallback)(function (source) {
193
+ /**
194
+ * Prevent tooltips from being shown during a drag. This can occur with
195
+ * the native drag and drop API, where some pointer events can fire
196
+ * when they should not and lead to jank with tooltips.
197
+ */
198
+ if (isDraggingRef.current) {
199
+ return;
200
+ }
169
201
  if (apiRef.current && !apiRef.current.isActive()) {
170
202
  abort();
171
203
  }
@@ -178,8 +210,8 @@ function Tooltip(_ref) {
178
210
  var entry = {
179
211
  source: source,
180
212
  delay: lastDelay.current,
181
- show: function show(_ref2) {
182
- var isImmediate = _ref2.isImmediate;
213
+ show: function show(_ref3) {
214
+ var isImmediate = _ref3.isImmediate;
183
215
  // Call the onShow handler if it hasn't been called yet
184
216
  if (!hasCalledShowHandler.current) {
185
217
  hasCalledShowHandler.current = true;
@@ -187,8 +219,8 @@ function Tooltip(_ref) {
187
219
  }
188
220
  setState(isImmediate ? 'show-immediate' : 'fade-in');
189
221
  },
190
- hide: function hide(_ref3) {
191
- var isImmediate = _ref3.isImmediate;
222
+ hide: function hide(_ref4) {
223
+ var isImmediate = _ref4.isImmediate;
192
224
  if (isImmediate) {
193
225
  setState('hide');
194
226
  } else {
@@ -201,8 +233,8 @@ function Tooltip(_ref) {
201
233
  start(api);
202
234
  }, [abort, done, start]);
203
235
  var hideTooltipOnEsc = (0, _react.useCallback)(function () {
204
- var _apiRef$current;
205
- (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || _apiRef$current.requestHide({
236
+ var _apiRef$current2;
237
+ (_apiRef$current2 = apiRef.current) === null || _apiRef$current2 === void 0 || _apiRef$current2.requestHide({
206
238
  isImmediate: true
207
239
  });
208
240
  }, [apiRef]);
@@ -301,8 +333,8 @@ function Tooltip(_ref) {
301
333
  }
302
334
  }, []);
303
335
  var onMouseMove = position === 'mouse' ? function (event) {
304
- var _apiRef$current2;
305
- if ((_apiRef$current2 = apiRef.current) !== null && _apiRef$current2 !== void 0 && _apiRef$current2.isActive()) {
336
+ var _apiRef$current3;
337
+ if ((_apiRef$current3 = apiRef.current) !== null && _apiRef$current3 !== void 0 && _apiRef$current3.isActive()) {
306
338
  apiRef.current.mousePosition = (0, _utilities.getMousePosition)({
307
339
  left: event.clientX,
308
340
  top: event.clientY
@@ -340,10 +372,10 @@ function Tooltip(_ref) {
340
372
  var shouldRenderTooltipContainer = state !== 'hide' && Boolean(content);
341
373
  var shouldRenderTooltipChildren = state !== 'hide' && state !== 'fade-out';
342
374
  var getReferenceElement = function getReferenceElement() {
343
- var _apiRef$current3;
344
- if (position === 'mouse' && (_apiRef$current3 = apiRef.current) !== null && _apiRef$current3 !== void 0 && _apiRef$current3.mousePosition) {
345
- var _apiRef$current4;
346
- return (_apiRef$current4 = apiRef.current) === null || _apiRef$current4 === void 0 ? void 0 : _apiRef$current4.mousePosition;
375
+ var _apiRef$current4;
376
+ if (position === 'mouse' && (_apiRef$current4 = apiRef.current) !== null && _apiRef$current4 !== void 0 && _apiRef$current4.mousePosition) {
377
+ var _apiRef$current5;
378
+ return (_apiRef$current5 = apiRef.current) === null || _apiRef$current5 === void 0 ? void 0 : _apiRef$current5.mousePosition;
347
379
  }
348
380
  return targetRef.current || undefined;
349
381
  };
@@ -397,11 +429,11 @@ function Tooltip(_ref) {
397
429
  placement: tooltipPosition,
398
430
  referenceElement: getReferenceElement(),
399
431
  strategy: strategy
400
- }, function (_ref4) {
401
- var ref = _ref4.ref,
402
- style = _ref4.style,
403
- update = _ref4.update,
404
- placement = _ref4.placement;
432
+ }, function (_ref5) {
433
+ var ref = _ref5.ref,
434
+ style = _ref5.style,
435
+ update = _ref5.update,
436
+ placement = _ref5.placement;
405
437
  // Invert the entrance and exit directions.
406
438
  // E.g. a tooltip's position is on the 'right', it should enter from and exit to the 'left'
407
439
  // This gives the effect the tooltip is appearing from the target
@@ -414,8 +446,8 @@ function Tooltip(_ref) {
414
446
  exitDirection: direction,
415
447
  onFinish: onAnimationFinished,
416
448
  duration: state === 'show-immediate' ? 0 : _durations.mediumDurationMs
417
- }, function (_ref5) {
418
- var className = _ref5.className;
449
+ }, function (_ref6) {
450
+ var className = _ref6.className;
419
451
  return (0, _react2.jsx)(Container, {
420
452
  ref: ref
421
453
  /**
@@ -8,7 +8,6 @@ exports.default = void 0;
8
8
  var _react = require("react");
9
9
  var _react2 = require("@emotion/react");
10
10
  var _colors = require("@atlaskit/theme/colors");
11
- var _components = _interopRequireDefault(require("@atlaskit/theme/components"));
12
11
  var _TooltipPrimitive = _interopRequireDefault(require("./TooltipPrimitive"));
13
12
  /** @jsx jsx */
14
13
 
@@ -22,7 +21,9 @@ var baseStyles = (0, _react2.css)({
22
21
  fontSize: "var(--ds-font-size-075, 12px)",
23
22
  lineHeight: 1.3,
24
23
  overflowWrap: 'break-word',
25
- wordWrap: 'break-word'
24
+ wordWrap: 'break-word',
25
+ backgroundColor: "var(--ds-background-neutral-bold, ".concat(_colors.N800, ")"),
26
+ color: "var(--ds-text-inverse, ".concat(_colors.N0, ")")
26
27
  });
27
28
  var truncateStyles = (0, _react2.css)({
28
29
  maxWidth: '420px',
@@ -30,14 +31,6 @@ var truncateStyles = (0, _react2.css)({
30
31
  textOverflow: 'ellipsis',
31
32
  whiteSpace: 'nowrap'
32
33
  });
33
- var lightStyles = (0, _react2.css)({
34
- backgroundColor: "var(--ds-background-neutral-bold, ".concat(_colors.N800, ")"),
35
- color: "var(--ds-text-inverse, ".concat(_colors.N0, ")")
36
- });
37
- var darkStyles = (0, _react2.css)({
38
- backgroundColor: "var(--ds-background-neutral-bold, ".concat(_colors.DN0, ")"),
39
- color: "var(--ds-text-inverse, ".concat(_colors.DN600, ")")
40
- });
41
34
  var TooltipContainer = /*#__PURE__*/(0, _react.forwardRef)(function TooltipContainer(_ref, ref) {
42
35
  var style = _ref.style,
43
36
  className = _ref.className,
@@ -48,20 +41,17 @@ var TooltipContainer = /*#__PURE__*/(0, _react.forwardRef)(function TooltipConta
48
41
  onMouseOut = _ref.onMouseOut,
49
42
  onMouseOver = _ref.onMouseOver,
50
43
  id = _ref.id;
51
- return (0, _react2.jsx)(_components.default.Consumer, null, function (_ref2) {
52
- var mode = _ref2.mode;
53
- return (0, _react2.jsx)(_TooltipPrimitive.default, {
54
- ref: ref,
55
- style: style,
56
- className: className,
57
- placement: placement,
58
- testId: testId,
59
- id: id,
60
- onMouseOut: onMouseOut,
61
- onMouseOver: onMouseOver,
62
- css: [baseStyles, truncate ? truncateStyles : null, mode === 'light' ? lightStyles : darkStyles]
63
- }, children);
64
- });
44
+ return (0, _react2.jsx)(_TooltipPrimitive.default, {
45
+ ref: ref,
46
+ style: style,
47
+ className: className,
48
+ placement: placement,
49
+ testId: testId,
50
+ id: id,
51
+ onMouseOut: onMouseOut,
52
+ onMouseOver: onMouseOver,
53
+ css: [baseStyles, truncate ? truncateStyles : null]
54
+ }, children);
65
55
  });
66
56
  TooltipContainer.displayName = 'TooltipContainer';
67
57
  var _default = exports.default = TooltipContainer;
@@ -32,9 +32,12 @@ var TooltipPrimitive = /*#__PURE__*/(0, _react.forwardRef)(function TooltipPrimi
32
32
  "data-testid": testId ? "".concat(testId, "--wrapper") : undefined
33
33
  }, (0, _react2.jsx)("div", {
34
34
  role: "tooltip",
35
- className: className,
35
+ className: className
36
+ // Because the tooltip should not be focusable, there is no reason to have key events.
37
+ /* eslint-disable jsx-a11y/mouse-events-have-key-events */,
36
38
  onMouseOut: onMouseOut,
37
- onMouseOver: onMouseOver,
39
+ onMouseOver: onMouseOver
40
+ /* eslint-enable jsx-a11y/mouse-events-have-key-events */,
38
41
  css: primitiveStyles,
39
42
  "data-placement": placement,
40
43
  "data-testid": testId,
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.register = register;
7
+ var _bindEventListener = require("bind-event-listener");
8
+ /**
9
+ * We are listening directly to drag events instead of using a monitor from
10
+ * `@atlaskit/pragmatic-drag-and-drop` to avoid the bundle size cost, as it
11
+ * would affect almost every view in every product.
12
+ *
13
+ * We can reconsider this choice in the future.
14
+ */
15
+
16
+ var registrations = new Set();
17
+ var cleanupEndEventListeners = null;
18
+ function onDragStart() {
19
+ if (cleanupEndEventListeners) {
20
+ // If the cleanup function exists then we've already run this
21
+ return;
22
+ }
23
+ cleanupEndEventListeners = (0, _bindEventListener.bindAll)(window, [{
24
+ type: 'dragend',
25
+ listener: onDragEnd
26
+ }, {
27
+ type: 'pointerdown',
28
+ listener: onDragEnd
29
+ }, {
30
+ type: 'pointermove',
31
+ listener: function () {
32
+ var callCount = 0;
33
+ return function listener() {
34
+ // Using 20 as it is far bigger than the most observed (3)
35
+ if (callCount < 20) {
36
+ callCount++;
37
+ return;
38
+ }
39
+ onDragEnd();
40
+ };
41
+ }()
42
+ }]);
43
+ var clone = Array.from(registrations);
44
+ clone.forEach(function (subscriber) {
45
+ subscriber.onDragStart();
46
+ });
47
+ }
48
+ function onDragEnd() {
49
+ var _cleanupEndEventListe;
50
+ (_cleanupEndEventListe = cleanupEndEventListeners) === null || _cleanupEndEventListe === void 0 || _cleanupEndEventListe();
51
+ cleanupEndEventListeners = null;
52
+ var clone = Array.from(registrations);
53
+ clone.forEach(function (subscriber) {
54
+ subscriber.onDragEnd();
55
+ });
56
+ }
57
+ function bindStartEvents() {
58
+ return (0, _bindEventListener.bindAll)(window, [{
59
+ type: 'dragstart',
60
+ listener: onDragStart
61
+ }, {
62
+ type: 'dragenter',
63
+ listener: onDragStart
64
+ }]);
65
+ }
66
+ var cleanupStartEventListeners = null;
67
+ function register(registration) {
68
+ // if first registration, bind event listeners
69
+ if (!cleanupStartEventListeners) {
70
+ // note: currently never unbinding these event listeners
71
+ cleanupStartEventListeners = bindStartEvents();
72
+ }
73
+ registrations.add(registration);
74
+
75
+ /**
76
+ * The reasoning for this behavior is so that if a tooltip mounts during
77
+ * a drag it can still be suppressed.
78
+ *
79
+ * We use a separate callback instead of onDragStart to avoid infinite loops.
80
+ */
81
+ registration.onRegister({
82
+ isDragging: cleanupEndEventListeners !== null
83
+ });
84
+ return function unregister() {
85
+ registrations.delete(registration);
86
+ if (registrations.size === 0) {
87
+ var _cleanupStartEventLis;
88
+ (_cleanupStartEventLis = cleanupStartEventListeners) === null || _cleanupStartEventLis === void 0 || _cleanupStartEventLis();
89
+ cleanupStartEventListeners = null;
90
+ }
91
+ };
92
+ }
@@ -12,6 +12,7 @@ import { mediumDurationMs } from '@atlaskit/motion/durations';
12
12
  import { Popper } from '@atlaskit/popper';
13
13
  import Portal from '@atlaskit/portal';
14
14
  import { layers } from '@atlaskit/theme/constants';
15
+ import { register } from './internal/drag-manager';
15
16
  import { show } from './internal/tooltip-manager';
16
17
  import useUniqueId from './internal/use-unique-id';
17
18
  import TooltipContainer from './TooltipContainer';
@@ -20,7 +21,7 @@ const tooltipZIndex = layers.tooltip();
20
21
  const analyticsAttributes = {
21
22
  componentName: 'tooltip',
22
23
  packageName: "@atlaskit/tooltip",
23
- packageVersion: "17.8.10"
24
+ packageVersion: "18.1.0"
24
25
  };
25
26
 
26
27
  // Inverts motion direction
@@ -140,7 +141,39 @@ function Tooltip({
140
141
  }
141
142
  };
142
143
  }, [abort]);
144
+ const isDraggingRef = useRef(false);
145
+ useEffect(() => {
146
+ return register({
147
+ onRegister({
148
+ isDragging
149
+ }) {
150
+ isDraggingRef.current = isDragging;
151
+ },
152
+ onDragStart() {
153
+ var _apiRef$current;
154
+ /**
155
+ * Hiding any visible tooltips when a drag starts because otherwise it
156
+ * looks janky (disappears and reappears), and is not required.
157
+ */
158
+ (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 ? void 0 : _apiRef$current.requestHide({
159
+ isImmediate: true
160
+ });
161
+ isDraggingRef.current = true;
162
+ },
163
+ onDragEnd() {
164
+ isDraggingRef.current = false;
165
+ }
166
+ });
167
+ }, []);
143
168
  const showTooltip = useCallback(source => {
169
+ /**
170
+ * Prevent tooltips from being shown during a drag. This can occur with
171
+ * the native drag and drop API, where some pointer events can fire
172
+ * when they should not and lead to jank with tooltips.
173
+ */
174
+ if (isDraggingRef.current) {
175
+ return;
176
+ }
144
177
  if (apiRef.current && !apiRef.current.isActive()) {
145
178
  abort();
146
179
  }
@@ -178,8 +211,8 @@ function Tooltip({
178
211
  start(api);
179
212
  }, [abort, done, start]);
180
213
  const hideTooltipOnEsc = useCallback(() => {
181
- var _apiRef$current;
182
- (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 ? void 0 : _apiRef$current.requestHide({
214
+ var _apiRef$current2;
215
+ (_apiRef$current2 = apiRef.current) === null || _apiRef$current2 === void 0 ? void 0 : _apiRef$current2.requestHide({
183
216
  isImmediate: true
184
217
  });
185
218
  }, [apiRef]);
@@ -278,8 +311,8 @@ function Tooltip({
278
311
  }
279
312
  }, []);
280
313
  const onMouseMove = position === 'mouse' ? event => {
281
- var _apiRef$current2;
282
- if ((_apiRef$current2 = apiRef.current) !== null && _apiRef$current2 !== void 0 && _apiRef$current2.isActive()) {
314
+ var _apiRef$current3;
315
+ if ((_apiRef$current3 = apiRef.current) !== null && _apiRef$current3 !== void 0 && _apiRef$current3.isActive()) {
283
316
  apiRef.current.mousePosition = getMousePosition({
284
317
  left: event.clientX,
285
318
  top: event.clientY
@@ -317,10 +350,10 @@ function Tooltip({
317
350
  const shouldRenderTooltipContainer = state !== 'hide' && Boolean(content);
318
351
  const shouldRenderTooltipChildren = state !== 'hide' && state !== 'fade-out';
319
352
  const getReferenceElement = () => {
320
- var _apiRef$current3;
321
- if (position === 'mouse' && (_apiRef$current3 = apiRef.current) !== null && _apiRef$current3 !== void 0 && _apiRef$current3.mousePosition) {
322
- var _apiRef$current4;
323
- return (_apiRef$current4 = apiRef.current) === null || _apiRef$current4 === void 0 ? void 0 : _apiRef$current4.mousePosition;
353
+ var _apiRef$current4;
354
+ if (position === 'mouse' && (_apiRef$current4 = apiRef.current) !== null && _apiRef$current4 !== void 0 && _apiRef$current4.mousePosition) {
355
+ var _apiRef$current5;
356
+ return (_apiRef$current5 = apiRef.current) === null || _apiRef$current5 === void 0 ? void 0 : _apiRef$current5.mousePosition;
324
357
  }
325
358
  return targetRef.current || undefined;
326
359
  };
@@ -1,8 +1,7 @@
1
1
  /** @jsx jsx */
2
2
  import { forwardRef } from 'react';
3
3
  import { css, jsx } from '@emotion/react';
4
- import { DN0, DN600, N0, N800 } from '@atlaskit/theme/colors';
5
- import GlobalTheme from '@atlaskit/theme/components';
4
+ import { N0, N800 } from '@atlaskit/theme/colors';
6
5
  import TooltipPrimitive from './TooltipPrimitive';
7
6
  const baseStyles = css({
8
7
  boxSizing: 'border-box',
@@ -14,7 +13,9 @@ const baseStyles = css({
14
13
  fontSize: "var(--ds-font-size-075, 12px)",
15
14
  lineHeight: 1.3,
16
15
  overflowWrap: 'break-word',
17
- wordWrap: 'break-word'
16
+ wordWrap: 'break-word',
17
+ backgroundColor: `var(--ds-background-neutral-bold, ${N800})`,
18
+ color: `var(--ds-text-inverse, ${N0})`
18
19
  });
19
20
  const truncateStyles = css({
20
21
  maxWidth: '420px',
@@ -22,14 +23,6 @@ const truncateStyles = css({
22
23
  textOverflow: 'ellipsis',
23
24
  whiteSpace: 'nowrap'
24
25
  });
25
- const lightStyles = css({
26
- backgroundColor: `var(--ds-background-neutral-bold, ${N800})`,
27
- color: `var(--ds-text-inverse, ${N0})`
28
- });
29
- const darkStyles = css({
30
- backgroundColor: `var(--ds-background-neutral-bold, ${DN0})`,
31
- color: `var(--ds-text-inverse, ${DN600})`
32
- });
33
26
  const TooltipContainer = /*#__PURE__*/forwardRef(function TooltipContainer({
34
27
  style,
35
28
  className,
@@ -41,9 +34,7 @@ const TooltipContainer = /*#__PURE__*/forwardRef(function TooltipContainer({
41
34
  onMouseOver,
42
35
  id
43
36
  }, ref) {
44
- return jsx(GlobalTheme.Consumer, null, ({
45
- mode
46
- }) => jsx(TooltipPrimitive, {
37
+ return jsx(TooltipPrimitive, {
47
38
  ref: ref,
48
39
  style: style,
49
40
  className: className,
@@ -52,8 +43,8 @@ const TooltipContainer = /*#__PURE__*/forwardRef(function TooltipContainer({
52
43
  id: id,
53
44
  onMouseOut: onMouseOut,
54
45
  onMouseOver: onMouseOver,
55
- css: [baseStyles, truncate ? truncateStyles : null, mode === 'light' ? lightStyles : darkStyles]
56
- }, children));
46
+ css: [baseStyles, truncate ? truncateStyles : null]
47
+ }, children);
57
48
  });
58
49
  TooltipContainer.displayName = 'TooltipContainer';
59
50
  export default TooltipContainer;
@@ -27,9 +27,12 @@ const TooltipPrimitive = /*#__PURE__*/forwardRef(function TooltipPrimitive({
27
27
  "data-testid": testId ? `${testId}--wrapper` : undefined
28
28
  }, jsx("div", {
29
29
  role: "tooltip",
30
- className: className,
30
+ className: className
31
+ // Because the tooltip should not be focusable, there is no reason to have key events.
32
+ /* eslint-disable jsx-a11y/mouse-events-have-key-events */,
31
33
  onMouseOut: onMouseOut,
32
- onMouseOver: onMouseOver,
34
+ onMouseOver: onMouseOver
35
+ /* eslint-enable jsx-a11y/mouse-events-have-key-events */,
33
36
  css: primitiveStyles,
34
37
  "data-placement": placement,
35
38
  "data-testid": testId,
@@ -0,0 +1,85 @@
1
+ /**
2
+ * We are listening directly to drag events instead of using a monitor from
3
+ * `@atlaskit/pragmatic-drag-and-drop` to avoid the bundle size cost, as it
4
+ * would affect almost every view in every product.
5
+ *
6
+ * We can reconsider this choice in the future.
7
+ */
8
+ import { bindAll } from 'bind-event-listener';
9
+ const registrations = new Set();
10
+ let cleanupEndEventListeners = null;
11
+ function onDragStart() {
12
+ if (cleanupEndEventListeners) {
13
+ // If the cleanup function exists then we've already run this
14
+ return;
15
+ }
16
+ cleanupEndEventListeners = bindAll(window, [{
17
+ type: 'dragend',
18
+ listener: onDragEnd
19
+ }, {
20
+ type: 'pointerdown',
21
+ listener: onDragEnd
22
+ }, {
23
+ type: 'pointermove',
24
+ listener: (() => {
25
+ let callCount = 0;
26
+ return function listener() {
27
+ // Using 20 as it is far bigger than the most observed (3)
28
+ if (callCount < 20) {
29
+ callCount++;
30
+ return;
31
+ }
32
+ onDragEnd();
33
+ };
34
+ })()
35
+ }]);
36
+ const clone = Array.from(registrations);
37
+ clone.forEach(subscriber => {
38
+ subscriber.onDragStart();
39
+ });
40
+ }
41
+ function onDragEnd() {
42
+ var _cleanupEndEventListe;
43
+ (_cleanupEndEventListe = cleanupEndEventListeners) === null || _cleanupEndEventListe === void 0 ? void 0 : _cleanupEndEventListe();
44
+ cleanupEndEventListeners = null;
45
+ const clone = Array.from(registrations);
46
+ clone.forEach(subscriber => {
47
+ subscriber.onDragEnd();
48
+ });
49
+ }
50
+ function bindStartEvents() {
51
+ return bindAll(window, [{
52
+ type: 'dragstart',
53
+ listener: onDragStart
54
+ }, {
55
+ type: 'dragenter',
56
+ listener: onDragStart
57
+ }]);
58
+ }
59
+ let cleanupStartEventListeners = null;
60
+ export function register(registration) {
61
+ // if first registration, bind event listeners
62
+ if (!cleanupStartEventListeners) {
63
+ // note: currently never unbinding these event listeners
64
+ cleanupStartEventListeners = bindStartEvents();
65
+ }
66
+ registrations.add(registration);
67
+
68
+ /**
69
+ * The reasoning for this behavior is so that if a tooltip mounts during
70
+ * a drag it can still be suppressed.
71
+ *
72
+ * We use a separate callback instead of onDragStart to avoid infinite loops.
73
+ */
74
+ registration.onRegister({
75
+ isDragging: cleanupEndEventListeners !== null
76
+ });
77
+ return function unregister() {
78
+ registrations.delete(registration);
79
+ if (registrations.size === 0) {
80
+ var _cleanupStartEventLis;
81
+ (_cleanupStartEventLis = cleanupStartEventListeners) === null || _cleanupStartEventLis === void 0 ? void 0 : _cleanupStartEventLis();
82
+ cleanupStartEventListeners = null;
83
+ }
84
+ };
85
+ }
@@ -16,6 +16,7 @@ import { mediumDurationMs } from '@atlaskit/motion/durations';
16
16
  import { Popper } from '@atlaskit/popper';
17
17
  import Portal from '@atlaskit/portal';
18
18
  import { layers } from '@atlaskit/theme/constants';
19
+ import { register } from './internal/drag-manager';
19
20
  import { show } from './internal/tooltip-manager';
20
21
  import useUniqueId from './internal/use-unique-id';
21
22
  import TooltipContainer from './TooltipContainer';
@@ -24,7 +25,7 @@ var tooltipZIndex = layers.tooltip();
24
25
  var analyticsAttributes = {
25
26
  componentName: 'tooltip',
26
27
  packageName: "@atlaskit/tooltip",
27
- packageVersion: "17.8.10"
28
+ packageVersion: "18.1.0"
28
29
  };
29
30
 
30
31
  // Inverts motion direction
@@ -157,7 +158,38 @@ function Tooltip(_ref) {
157
158
  }
158
159
  };
159
160
  }, [abort]);
161
+ var isDraggingRef = useRef(false);
162
+ useEffect(function () {
163
+ return register({
164
+ onRegister: function onRegister(_ref2) {
165
+ var isDragging = _ref2.isDragging;
166
+ isDraggingRef.current = isDragging;
167
+ },
168
+ onDragStart: function onDragStart() {
169
+ var _apiRef$current;
170
+ /**
171
+ * Hiding any visible tooltips when a drag starts because otherwise it
172
+ * looks janky (disappears and reappears), and is not required.
173
+ */
174
+ (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || _apiRef$current.requestHide({
175
+ isImmediate: true
176
+ });
177
+ isDraggingRef.current = true;
178
+ },
179
+ onDragEnd: function onDragEnd() {
180
+ isDraggingRef.current = false;
181
+ }
182
+ });
183
+ }, []);
160
184
  var showTooltip = useCallback(function (source) {
185
+ /**
186
+ * Prevent tooltips from being shown during a drag. This can occur with
187
+ * the native drag and drop API, where some pointer events can fire
188
+ * when they should not and lead to jank with tooltips.
189
+ */
190
+ if (isDraggingRef.current) {
191
+ return;
192
+ }
161
193
  if (apiRef.current && !apiRef.current.isActive()) {
162
194
  abort();
163
195
  }
@@ -170,8 +202,8 @@ function Tooltip(_ref) {
170
202
  var entry = {
171
203
  source: source,
172
204
  delay: lastDelay.current,
173
- show: function show(_ref2) {
174
- var isImmediate = _ref2.isImmediate;
205
+ show: function show(_ref3) {
206
+ var isImmediate = _ref3.isImmediate;
175
207
  // Call the onShow handler if it hasn't been called yet
176
208
  if (!hasCalledShowHandler.current) {
177
209
  hasCalledShowHandler.current = true;
@@ -179,8 +211,8 @@ function Tooltip(_ref) {
179
211
  }
180
212
  setState(isImmediate ? 'show-immediate' : 'fade-in');
181
213
  },
182
- hide: function hide(_ref3) {
183
- var isImmediate = _ref3.isImmediate;
214
+ hide: function hide(_ref4) {
215
+ var isImmediate = _ref4.isImmediate;
184
216
  if (isImmediate) {
185
217
  setState('hide');
186
218
  } else {
@@ -193,8 +225,8 @@ function Tooltip(_ref) {
193
225
  start(api);
194
226
  }, [abort, done, start]);
195
227
  var hideTooltipOnEsc = useCallback(function () {
196
- var _apiRef$current;
197
- (_apiRef$current = apiRef.current) === null || _apiRef$current === void 0 || _apiRef$current.requestHide({
228
+ var _apiRef$current2;
229
+ (_apiRef$current2 = apiRef.current) === null || _apiRef$current2 === void 0 || _apiRef$current2.requestHide({
198
230
  isImmediate: true
199
231
  });
200
232
  }, [apiRef]);
@@ -293,8 +325,8 @@ function Tooltip(_ref) {
293
325
  }
294
326
  }, []);
295
327
  var onMouseMove = position === 'mouse' ? function (event) {
296
- var _apiRef$current2;
297
- if ((_apiRef$current2 = apiRef.current) !== null && _apiRef$current2 !== void 0 && _apiRef$current2.isActive()) {
328
+ var _apiRef$current3;
329
+ if ((_apiRef$current3 = apiRef.current) !== null && _apiRef$current3 !== void 0 && _apiRef$current3.isActive()) {
298
330
  apiRef.current.mousePosition = getMousePosition({
299
331
  left: event.clientX,
300
332
  top: event.clientY
@@ -332,10 +364,10 @@ function Tooltip(_ref) {
332
364
  var shouldRenderTooltipContainer = state !== 'hide' && Boolean(content);
333
365
  var shouldRenderTooltipChildren = state !== 'hide' && state !== 'fade-out';
334
366
  var getReferenceElement = function getReferenceElement() {
335
- var _apiRef$current3;
336
- if (position === 'mouse' && (_apiRef$current3 = apiRef.current) !== null && _apiRef$current3 !== void 0 && _apiRef$current3.mousePosition) {
337
- var _apiRef$current4;
338
- return (_apiRef$current4 = apiRef.current) === null || _apiRef$current4 === void 0 ? void 0 : _apiRef$current4.mousePosition;
367
+ var _apiRef$current4;
368
+ if (position === 'mouse' && (_apiRef$current4 = apiRef.current) !== null && _apiRef$current4 !== void 0 && _apiRef$current4.mousePosition) {
369
+ var _apiRef$current5;
370
+ return (_apiRef$current5 = apiRef.current) === null || _apiRef$current5 === void 0 ? void 0 : _apiRef$current5.mousePosition;
339
371
  }
340
372
  return targetRef.current || undefined;
341
373
  };
@@ -389,11 +421,11 @@ function Tooltip(_ref) {
389
421
  placement: tooltipPosition,
390
422
  referenceElement: getReferenceElement(),
391
423
  strategy: strategy
392
- }, function (_ref4) {
393
- var ref = _ref4.ref,
394
- style = _ref4.style,
395
- update = _ref4.update,
396
- placement = _ref4.placement;
424
+ }, function (_ref5) {
425
+ var ref = _ref5.ref,
426
+ style = _ref5.style,
427
+ update = _ref5.update,
428
+ placement = _ref5.placement;
397
429
  // Invert the entrance and exit directions.
398
430
  // E.g. a tooltip's position is on the 'right', it should enter from and exit to the 'left'
399
431
  // This gives the effect the tooltip is appearing from the target
@@ -406,8 +438,8 @@ function Tooltip(_ref) {
406
438
  exitDirection: direction,
407
439
  onFinish: onAnimationFinished,
408
440
  duration: state === 'show-immediate' ? 0 : mediumDurationMs
409
- }, function (_ref5) {
410
- var className = _ref5.className;
441
+ }, function (_ref6) {
442
+ var className = _ref6.className;
411
443
  return jsx(Container, {
412
444
  ref: ref
413
445
  /**
@@ -1,8 +1,7 @@
1
1
  /** @jsx jsx */
2
2
  import { forwardRef } from 'react';
3
3
  import { css, jsx } from '@emotion/react';
4
- import { DN0, DN600, N0, N800 } from '@atlaskit/theme/colors';
5
- import GlobalTheme from '@atlaskit/theme/components';
4
+ import { N0, N800 } from '@atlaskit/theme/colors';
6
5
  import TooltipPrimitive from './TooltipPrimitive';
7
6
  var baseStyles = css({
8
7
  boxSizing: 'border-box',
@@ -14,7 +13,9 @@ var baseStyles = css({
14
13
  fontSize: "var(--ds-font-size-075, 12px)",
15
14
  lineHeight: 1.3,
16
15
  overflowWrap: 'break-word',
17
- wordWrap: 'break-word'
16
+ wordWrap: 'break-word',
17
+ backgroundColor: "var(--ds-background-neutral-bold, ".concat(N800, ")"),
18
+ color: "var(--ds-text-inverse, ".concat(N0, ")")
18
19
  });
19
20
  var truncateStyles = css({
20
21
  maxWidth: '420px',
@@ -22,14 +23,6 @@ var truncateStyles = css({
22
23
  textOverflow: 'ellipsis',
23
24
  whiteSpace: 'nowrap'
24
25
  });
25
- var lightStyles = css({
26
- backgroundColor: "var(--ds-background-neutral-bold, ".concat(N800, ")"),
27
- color: "var(--ds-text-inverse, ".concat(N0, ")")
28
- });
29
- var darkStyles = css({
30
- backgroundColor: "var(--ds-background-neutral-bold, ".concat(DN0, ")"),
31
- color: "var(--ds-text-inverse, ".concat(DN600, ")")
32
- });
33
26
  var TooltipContainer = /*#__PURE__*/forwardRef(function TooltipContainer(_ref, ref) {
34
27
  var style = _ref.style,
35
28
  className = _ref.className,
@@ -40,20 +33,17 @@ var TooltipContainer = /*#__PURE__*/forwardRef(function TooltipContainer(_ref, r
40
33
  onMouseOut = _ref.onMouseOut,
41
34
  onMouseOver = _ref.onMouseOver,
42
35
  id = _ref.id;
43
- return jsx(GlobalTheme.Consumer, null, function (_ref2) {
44
- var mode = _ref2.mode;
45
- return jsx(TooltipPrimitive, {
46
- ref: ref,
47
- style: style,
48
- className: className,
49
- placement: placement,
50
- testId: testId,
51
- id: id,
52
- onMouseOut: onMouseOut,
53
- onMouseOver: onMouseOver,
54
- css: [baseStyles, truncate ? truncateStyles : null, mode === 'light' ? lightStyles : darkStyles]
55
- }, children);
56
- });
36
+ return jsx(TooltipPrimitive, {
37
+ ref: ref,
38
+ style: style,
39
+ className: className,
40
+ placement: placement,
41
+ testId: testId,
42
+ id: id,
43
+ onMouseOut: onMouseOut,
44
+ onMouseOver: onMouseOver,
45
+ css: [baseStyles, truncate ? truncateStyles : null]
46
+ }, children);
57
47
  });
58
48
  TooltipContainer.displayName = 'TooltipContainer';
59
49
  export default TooltipContainer;
@@ -26,9 +26,12 @@ var TooltipPrimitive = /*#__PURE__*/forwardRef(function TooltipPrimitive(_ref, r
26
26
  "data-testid": testId ? "".concat(testId, "--wrapper") : undefined
27
27
  }, jsx("div", {
28
28
  role: "tooltip",
29
- className: className,
29
+ className: className
30
+ // Because the tooltip should not be focusable, there is no reason to have key events.
31
+ /* eslint-disable jsx-a11y/mouse-events-have-key-events */,
30
32
  onMouseOut: onMouseOut,
31
- onMouseOver: onMouseOver,
33
+ onMouseOver: onMouseOver
34
+ /* eslint-enable jsx-a11y/mouse-events-have-key-events */,
32
35
  css: primitiveStyles,
33
36
  "data-placement": placement,
34
37
  "data-testid": testId,
@@ -0,0 +1,85 @@
1
+ /**
2
+ * We are listening directly to drag events instead of using a monitor from
3
+ * `@atlaskit/pragmatic-drag-and-drop` to avoid the bundle size cost, as it
4
+ * would affect almost every view in every product.
5
+ *
6
+ * We can reconsider this choice in the future.
7
+ */
8
+ import { bindAll } from 'bind-event-listener';
9
+ var registrations = new Set();
10
+ var cleanupEndEventListeners = null;
11
+ function onDragStart() {
12
+ if (cleanupEndEventListeners) {
13
+ // If the cleanup function exists then we've already run this
14
+ return;
15
+ }
16
+ cleanupEndEventListeners = bindAll(window, [{
17
+ type: 'dragend',
18
+ listener: onDragEnd
19
+ }, {
20
+ type: 'pointerdown',
21
+ listener: onDragEnd
22
+ }, {
23
+ type: 'pointermove',
24
+ listener: function () {
25
+ var callCount = 0;
26
+ return function listener() {
27
+ // Using 20 as it is far bigger than the most observed (3)
28
+ if (callCount < 20) {
29
+ callCount++;
30
+ return;
31
+ }
32
+ onDragEnd();
33
+ };
34
+ }()
35
+ }]);
36
+ var clone = Array.from(registrations);
37
+ clone.forEach(function (subscriber) {
38
+ subscriber.onDragStart();
39
+ });
40
+ }
41
+ function onDragEnd() {
42
+ var _cleanupEndEventListe;
43
+ (_cleanupEndEventListe = cleanupEndEventListeners) === null || _cleanupEndEventListe === void 0 || _cleanupEndEventListe();
44
+ cleanupEndEventListeners = null;
45
+ var clone = Array.from(registrations);
46
+ clone.forEach(function (subscriber) {
47
+ subscriber.onDragEnd();
48
+ });
49
+ }
50
+ function bindStartEvents() {
51
+ return bindAll(window, [{
52
+ type: 'dragstart',
53
+ listener: onDragStart
54
+ }, {
55
+ type: 'dragenter',
56
+ listener: onDragStart
57
+ }]);
58
+ }
59
+ var cleanupStartEventListeners = null;
60
+ export function register(registration) {
61
+ // if first registration, bind event listeners
62
+ if (!cleanupStartEventListeners) {
63
+ // note: currently never unbinding these event listeners
64
+ cleanupStartEventListeners = bindStartEvents();
65
+ }
66
+ registrations.add(registration);
67
+
68
+ /**
69
+ * The reasoning for this behavior is so that if a tooltip mounts during
70
+ * a drag it can still be suppressed.
71
+ *
72
+ * We use a separate callback instead of onDragStart to avoid infinite loops.
73
+ */
74
+ registration.onRegister({
75
+ isDragging: cleanupEndEventListeners !== null
76
+ });
77
+ return function unregister() {
78
+ registrations.delete(registration);
79
+ if (registrations.size === 0) {
80
+ var _cleanupStartEventLis;
81
+ (_cleanupStartEventLis = cleanupStartEventListeners) === null || _cleanupStartEventLis === void 0 || _cleanupStartEventLis();
82
+ cleanupStartEventListeners = null;
83
+ }
84
+ };
85
+ }
@@ -0,0 +1,10 @@
1
+ type Registration = {
2
+ onRegister: (args: {
3
+ isDragging: boolean;
4
+ }) => void;
5
+ onDragStart: () => void;
6
+ onDragEnd: () => void;
7
+ };
8
+ type CleanupFn = () => void;
9
+ export declare function register(registration: Registration): CleanupFn;
10
+ export {};
@@ -0,0 +1,10 @@
1
+ type Registration = {
2
+ onRegister: (args: {
3
+ isDragging: boolean;
4
+ }) => void;
5
+ onDragStart: () => void;
6
+ onDragEnd: () => void;
7
+ };
8
+ type CleanupFn = () => void;
9
+ export declare function register(registration: Registration): CleanupFn;
10
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/tooltip",
3
- "version": "17.8.10",
3
+ "version": "18.1.0",
4
4
  "description": "A tooltip is a floating, non-actionable label used to explain a user interface element or feature.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -48,7 +48,7 @@
48
48
  "@atlaskit/popper": "^5.5.0",
49
49
  "@atlaskit/portal": "^4.4.0",
50
50
  "@atlaskit/theme": "^12.6.0",
51
- "@atlaskit/tokens": "^1.28.0",
51
+ "@atlaskit/tokens": "^1.30.0",
52
52
  "@babel/runtime": "^7.0.0",
53
53
  "@emotion/react": "^11.7.1",
54
54
  "bind-event-listener": "^2.1.1",
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "devDependencies": {
62
62
  "@af/accessibility-testing": "*",
63
- "@atlaskit/button": "^16.13.0",
63
+ "@atlaskit/button": "^17.1.0",
64
64
  "@atlaskit/ssr": "*",
65
65
  "@atlaskit/visual-regression": "*",
66
66
  "@atlassian/atlassian-frontend-prettier-config-1.0.1": "npm:@atlassian/atlassian-frontend-prettier-config@1.0.1",
@@ -1,106 +0,0 @@
1
- ## API Report File for "@atlaskit/tooltip"
2
-
3
- > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4
-
5
- ```ts
6
-
7
- import { ComponentType } from 'react';
8
- import { CSSProperties } from 'react';
9
- import { ForwardRefExoticComponent } from 'react';
10
- import { jsx } from '@emotion/react';
11
- import { Placement } from '@atlaskit/popper';
12
- import { ReactNode } from 'react';
13
- import { RefAttributes } from 'react';
14
- import { UIAnalyticsEvent } from '@atlaskit/analytics-next';
15
-
16
- // @public (undocumented)
17
- export type PositionType = 'mouse' | PositionTypeBase;
18
-
19
- // @public (undocumented)
20
- type PositionTypeBase = Placement;
21
-
22
- // @public (undocumented)
23
- function Tooltip({ children, position, mousePosition, content, truncate, component: Container, tag: TargetContainer, testId, delay, onShow, onHide, hideTooltipOnClick, hideTooltipOnMouseDown, analyticsContext, strategy, }: TooltipProps): jsx.JSX.Element;
24
-
25
- // @public (undocumented)
26
- namespace Tooltip {
27
- var // (undocumented)
28
- displayName: string;
29
- }
30
- export default Tooltip;
31
-
32
- // @public (undocumented)
33
- export const TooltipPrimitive: ForwardRefExoticComponent<Pick<TooltipPrimitiveProps, "children" | "className" | "id" | "onMouseOut" | "onMouseOver" | "placement" | "style" | "testId" | "truncate"> & RefAttributes<HTMLDivElement>>;
34
-
35
- // @public (undocumented)
36
- export interface TooltipPrimitiveProps {
37
- // (undocumented)
38
- children: ReactNode;
39
- // (undocumented)
40
- className?: string;
41
- // (undocumented)
42
- id?: string;
43
- // (undocumented)
44
- onMouseOut?: (e: React.MouseEvent<HTMLElement>) => void;
45
- // (undocumented)
46
- onMouseOver?: (e: React.MouseEvent<HTMLElement>) => void;
47
- // (undocumented)
48
- placement: PositionType;
49
- // (undocumented)
50
- ref: React.Ref<any>;
51
- // (undocumented)
52
- style?: CSSProperties;
53
- // (undocumented)
54
- testId?: string;
55
- // (undocumented)
56
- truncate?: boolean;
57
- }
58
-
59
- // @public (undocumented)
60
- export interface TooltipProps {
61
- analyticsContext?: Record<string, any>;
62
- children: ((props: TriggerProps) => ReactNode) | ReactNode;
63
- component?: ComponentType<TooltipPrimitiveProps>;
64
- content: (({ update }: {
65
- update: () => void;
66
- }) => ReactNode) | ReactNode;
67
- delay?: number;
68
- hideTooltipOnClick?: boolean;
69
- hideTooltipOnMouseDown?: boolean;
70
- mousePosition?: PositionTypeBase;
71
- onHide?: (analyticsEvent: UIAnalyticsEvent) => void;
72
- onShow?: (analyticsEvent: UIAnalyticsEvent) => void;
73
- position?: PositionType;
74
- strategy?: 'absolute' | 'fixed' | undefined;
75
- tag?: React.ComponentType<React.AllHTMLAttributes<HTMLElement> & {
76
- ref: React.Ref<HTMLElement>;
77
- }> | keyof JSX.IntrinsicElements;
78
- testId?: string;
79
- truncate?: boolean;
80
- }
81
-
82
- // @public (undocumented)
83
- interface TriggerProps {
84
- // (undocumented)
85
- 'aria-describedby'?: string | undefined;
86
- // (undocumented)
87
- onBlur: (event: React.FocusEvent<HTMLElement>) => void;
88
- // (undocumented)
89
- onClick: (event: React.MouseEvent<HTMLElement>) => void;
90
- // (undocumented)
91
- onFocus: (event: React.FocusEvent<HTMLElement>) => void;
92
- // (undocumented)
93
- onMouseDown: (event: React.MouseEvent<HTMLElement>) => void;
94
- // (undocumented)
95
- onMouseMove: ((event: React.MouseEvent<HTMLElement>) => void) | undefined;
96
- // (undocumented)
97
- onMouseOut: (event: React.MouseEvent<HTMLElement>) => void;
98
- // (undocumented)
99
- onMouseOver: (event: React.MouseEvent<HTMLElement>) => void;
100
- // (undocumented)
101
- ref: (node: HTMLElement | null) => void;
102
- }
103
-
104
- // (No @packageDocumentation comment for this package)
105
-
106
- ```