@atlaskit/teams-app-internal-popup-adaptor 1.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 +10 -0
- package/README.md +17 -0
- package/__tests__/unit/PopupTriggerWithHover.test.tsx +141 -0
- package/__tests__/unit/useHoverDelay.test.tsx +99 -0
- package/__tests__/unit/useHoverTriggerRef.test.tsx +121 -0
- package/__tests__/unit/usePreloadRef.test.tsx +118 -0
- package/__tests__/unit/usePressableTriggerRef.test.tsx +104 -0
- package/__tests__/unit/utils.test.tsx +86 -0
- package/afm-cc/tsconfig.json +40 -0
- package/afm-products/tsconfig.json +40 -0
- package/dist/cjs/PopupTriggerWithHover.js +158 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/useHoverDelay.js +38 -0
- package/dist/cjs/useHoverTriggerRef.js +155 -0
- package/dist/cjs/usePreloadRef.js +119 -0
- package/dist/cjs/usePressableTriggerRef.js +69 -0
- package/dist/cjs/utils.js +48 -0
- package/dist/es2019/PopupTriggerWithHover.js +139 -0
- package/dist/es2019/index.js +1 -0
- package/dist/es2019/useHoverDelay.js +32 -0
- package/dist/es2019/useHoverTriggerRef.js +139 -0
- package/dist/es2019/usePreloadRef.js +115 -0
- package/dist/es2019/usePressableTriggerRef.js +62 -0
- package/dist/es2019/utils.js +40 -0
- package/dist/esm/PopupTriggerWithHover.js +149 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/useHoverDelay.js +34 -0
- package/dist/esm/useHoverTriggerRef.js +149 -0
- package/dist/esm/usePreloadRef.js +113 -0
- package/dist/esm/usePressableTriggerRef.js +63 -0
- package/dist/esm/utils.js +41 -0
- package/dist/types/PopupTriggerWithHover.d.ts +28 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/useHoverDelay.d.ts +8 -0
- package/dist/types/useHoverTriggerRef.d.ts +19 -0
- package/dist/types/usePreloadRef.d.ts +13 -0
- package/dist/types/usePressableTriggerRef.d.ts +9 -0
- package/dist/types/utils.d.ts +16 -0
- package/dist/types-ts4.5/PopupTriggerWithHover.d.ts +28 -0
- package/dist/types-ts4.5/index.d.ts +1 -0
- package/dist/types-ts4.5/useHoverDelay.d.ts +8 -0
- package/dist/types-ts4.5/useHoverTriggerRef.d.ts +19 -0
- package/dist/types-ts4.5/usePreloadRef.d.ts +13 -0
- package/dist/types-ts4.5/usePressableTriggerRef.d.ts +9 -0
- package/dist/types-ts4.5/utils.d.ts +16 -0
- package/package.json +81 -0
- package/popup-trigger-with-hover/package.json +17 -0
- package/src/PopupTriggerWithHover.tsx +240 -0
- package/src/index.ts +5 -0
- package/src/useHoverDelay.ts +42 -0
- package/src/useHoverTriggerRef.ts +177 -0
- package/src/usePreloadRef.ts +152 -0
- package/src/usePressableTriggerRef.ts +89 -0
- package/src/utils.ts +49 -0
- package/tsconfig.app.json +46 -0
- package/tsconfig.dev.json +45 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hook for managing delayed hover actions with timeout management.
|
|
5
|
+
*/
|
|
6
|
+
function useHoverDelay(callback, delay) {
|
|
7
|
+
var timeoutRef = useRef(null);
|
|
8
|
+
var callbackRef = useRef(callback);
|
|
9
|
+
useEffect(function () {
|
|
10
|
+
callbackRef.current = callback;
|
|
11
|
+
}, [callback]);
|
|
12
|
+
var clear = useCallback(function () {
|
|
13
|
+
if (timeoutRef.current) {
|
|
14
|
+
clearTimeout(timeoutRef.current);
|
|
15
|
+
timeoutRef.current = null;
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
var schedule = useCallback(function () {
|
|
19
|
+
clear();
|
|
20
|
+
timeoutRef.current = window.setTimeout(function () {
|
|
21
|
+
callbackRef.current();
|
|
22
|
+
}, delay);
|
|
23
|
+
}, [delay, clear]);
|
|
24
|
+
useEffect(function () {
|
|
25
|
+
return function () {
|
|
26
|
+
return clear();
|
|
27
|
+
};
|
|
28
|
+
}, [clear]);
|
|
29
|
+
return {
|
|
30
|
+
schedule: schedule,
|
|
31
|
+
clear: clear
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export { useHoverDelay };
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
|
|
2
|
+
import { bind } from 'bind-event-listener';
|
|
3
|
+
import { useHoverDelay } from './useHoverDelay';
|
|
4
|
+
import { getChildPortalFromParentPopup, hasRelatedTarget, isMovingToKudos } from './utils';
|
|
5
|
+
var HOVER_OPEN_DELAY = 800;
|
|
6
|
+
var HOVER_CLOSE_DELAY = 200;
|
|
7
|
+
/**
|
|
8
|
+
* Hover behavior for popup trigger and content with delayed open/close.
|
|
9
|
+
*/
|
|
10
|
+
export function useHoverTriggerRef(_ref) {
|
|
11
|
+
var onOpen = _ref.onOpen,
|
|
12
|
+
onClose = _ref.onClose,
|
|
13
|
+
_ref$isOpen = _ref.isOpen,
|
|
14
|
+
isOpen = _ref$isOpen === void 0 ? false : _ref$isOpen,
|
|
15
|
+
_ref$isDisabled = _ref.isDisabled,
|
|
16
|
+
isDisabled = _ref$isDisabled === void 0 ? false : _ref$isDisabled,
|
|
17
|
+
openedByRef = _ref.openedByRef,
|
|
18
|
+
_ref$delays = _ref.delays,
|
|
19
|
+
delays = _ref$delays === void 0 ? {} : _ref$delays;
|
|
20
|
+
var _delays$hoverOpen = delays.hoverOpen,
|
|
21
|
+
hoverOpen = _delays$hoverOpen === void 0 ? HOVER_OPEN_DELAY : _delays$hoverOpen,
|
|
22
|
+
_delays$hoverClose = delays.hoverClose,
|
|
23
|
+
hoverClose = _delays$hoverClose === void 0 ? HOVER_CLOSE_DELAY : _delays$hoverClose;
|
|
24
|
+
var triggerNodeRef = useRef(null);
|
|
25
|
+
var triggerListeners = useRef([]);
|
|
26
|
+
var contentNodeRef = useRef(null);
|
|
27
|
+
var contentListeners = useRef(new Map());
|
|
28
|
+
var isOpenRef = useRef(isOpen);
|
|
29
|
+
useLayoutEffect(function () {
|
|
30
|
+
isOpenRef.current = isOpen;
|
|
31
|
+
}, [isOpen]);
|
|
32
|
+
var openDelay = useHoverDelay(function () {
|
|
33
|
+
if (isOpenRef.current) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (openedByRef) {
|
|
37
|
+
openedByRef.current = 'hover';
|
|
38
|
+
}
|
|
39
|
+
onOpen();
|
|
40
|
+
}, hoverOpen);
|
|
41
|
+
var closeDelay = useHoverDelay(function () {
|
|
42
|
+
if (!isOpenRef.current) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!openedByRef || openedByRef.current === 'hover') {
|
|
46
|
+
onClose === null || onClose === void 0 || onClose();
|
|
47
|
+
}
|
|
48
|
+
}, hoverClose);
|
|
49
|
+
var openDelayRef = useRef(openDelay);
|
|
50
|
+
var closeDelayRef = useRef(closeDelay);
|
|
51
|
+
openDelayRef.current = openDelay;
|
|
52
|
+
closeDelayRef.current = closeDelay;
|
|
53
|
+
var handleTriggerEnter = useCallback(function () {
|
|
54
|
+
closeDelayRef.current.clear();
|
|
55
|
+
openDelayRef.current.schedule();
|
|
56
|
+
}, []);
|
|
57
|
+
var handleTriggerLeave = useCallback(function () {
|
|
58
|
+
openDelayRef.current.clear();
|
|
59
|
+
closeDelayRef.current.schedule();
|
|
60
|
+
}, []);
|
|
61
|
+
var triggerRef = useCallback(function (element) {
|
|
62
|
+
if (element === triggerNodeRef.current) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
triggerListeners.current.forEach(function (unbind) {
|
|
66
|
+
return unbind();
|
|
67
|
+
});
|
|
68
|
+
triggerListeners.current = [];
|
|
69
|
+
triggerNodeRef.current = element;
|
|
70
|
+
if (element && !isDisabled) {
|
|
71
|
+
triggerListeners.current.push(bind(element, {
|
|
72
|
+
type: 'mouseenter',
|
|
73
|
+
listener: handleTriggerEnter
|
|
74
|
+
}), bind(element, {
|
|
75
|
+
type: 'mouseleave',
|
|
76
|
+
listener: handleTriggerLeave
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
}, [handleTriggerEnter, handleTriggerLeave, isDisabled]);
|
|
80
|
+
var handleContentEnter = useCallback(function () {
|
|
81
|
+
closeDelayRef.current.clear();
|
|
82
|
+
}, []);
|
|
83
|
+
var cleanupContentListeners = useCallback(function () {
|
|
84
|
+
contentListeners.current.forEach(function (unbind) {
|
|
85
|
+
return unbind();
|
|
86
|
+
});
|
|
87
|
+
contentListeners.current.clear();
|
|
88
|
+
}, []);
|
|
89
|
+
var attachContentListeners = useCallback(function (element) {
|
|
90
|
+
if (contentListeners.current.has(element)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
var handleMouseLeave = function handleMouseLeave(event) {
|
|
94
|
+
if (!hasRelatedTarget(event)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
var relatedTarget = event.relatedTarget;
|
|
98
|
+
if (isMovingToKudos(relatedTarget)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
var childPortal = getChildPortalFromParentPopup(relatedTarget, contentNodeRef.current);
|
|
102
|
+
if (childPortal) {
|
|
103
|
+
attachContentListeners(childPortal);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
closeDelayRef.current.schedule();
|
|
107
|
+
};
|
|
108
|
+
var unbindEnter = bind(element, {
|
|
109
|
+
type: 'mouseenter',
|
|
110
|
+
listener: handleContentEnter
|
|
111
|
+
});
|
|
112
|
+
var unbindLeave = bind(element, {
|
|
113
|
+
type: 'mouseleave',
|
|
114
|
+
listener: handleMouseLeave
|
|
115
|
+
});
|
|
116
|
+
contentListeners.current.set(element, function () {
|
|
117
|
+
unbindEnter();
|
|
118
|
+
unbindLeave();
|
|
119
|
+
});
|
|
120
|
+
}, [handleContentEnter]);
|
|
121
|
+
var contentRef = useCallback(function (element) {
|
|
122
|
+
if (element === contentNodeRef.current) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
cleanupContentListeners();
|
|
126
|
+
contentNodeRef.current = element;
|
|
127
|
+
if (element && !isDisabled) {
|
|
128
|
+
attachContentListeners(element);
|
|
129
|
+
}
|
|
130
|
+
}, [attachContentListeners, cleanupContentListeners, isDisabled]);
|
|
131
|
+
useEffect(function () {
|
|
132
|
+
var listeners = contentListeners.current;
|
|
133
|
+
var triggers = triggerListeners.current;
|
|
134
|
+
return function () {
|
|
135
|
+
openDelayRef.current.clear();
|
|
136
|
+
closeDelayRef.current.clear();
|
|
137
|
+
triggers.forEach(function (unbind) {
|
|
138
|
+
return unbind();
|
|
139
|
+
});
|
|
140
|
+
listeners.forEach(function (unbind) {
|
|
141
|
+
return unbind();
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
}, []);
|
|
145
|
+
return {
|
|
146
|
+
triggerRef: triggerRef,
|
|
147
|
+
contentRef: contentRef
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { bind } from 'bind-event-listener';
|
|
3
|
+
var PRELOAD_MAX_AGE = 5 * 60 * 1000;
|
|
4
|
+
var TIME_TO_INTENT = 200;
|
|
5
|
+
export function usePreloadRef(_ref) {
|
|
6
|
+
var load = _ref.load,
|
|
7
|
+
onLoad = _ref.onLoad;
|
|
8
|
+
var nodeRef = useRef(null);
|
|
9
|
+
var eventListeners = useRef([]);
|
|
10
|
+
var _useMemo = useMemo(function () {
|
|
11
|
+
var request = {};
|
|
12
|
+
var clearPreloadTimeouts = function clearPreloadTimeouts() {
|
|
13
|
+
if (request.preloadIntentTimeout != null) {
|
|
14
|
+
clearTimeout(request.preloadIntentTimeout);
|
|
15
|
+
delete request.preloadIntentTimeout;
|
|
16
|
+
}
|
|
17
|
+
if (request.preloadMaxAgeTimeout != null) {
|
|
18
|
+
clearTimeout(request.preloadMaxAgeTimeout);
|
|
19
|
+
delete request.preloadMaxAgeTimeout;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var cancelPreload = function cancelPreload() {
|
|
23
|
+
var _request$preload;
|
|
24
|
+
clearPreloadTimeouts();
|
|
25
|
+
(_request$preload = request.preload) === null || _request$preload === void 0 || _request$preload.dispose();
|
|
26
|
+
};
|
|
27
|
+
var loadReference = function loadReference() {
|
|
28
|
+
var _request$preload$refe, _request$preload2;
|
|
29
|
+
if (request.load) {
|
|
30
|
+
return request.load;
|
|
31
|
+
}
|
|
32
|
+
var reference = (_request$preload$refe = (_request$preload2 = request.preload) === null || _request$preload2 === void 0 ? void 0 : _request$preload2.reference) !== null && _request$preload$refe !== void 0 ? _request$preload$refe : load();
|
|
33
|
+
if (request.preload) {
|
|
34
|
+
delete request.preload;
|
|
35
|
+
}
|
|
36
|
+
request.load = {
|
|
37
|
+
reference: reference,
|
|
38
|
+
dispose: function dispose() {
|
|
39
|
+
reference.dispose();
|
|
40
|
+
delete request.load;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
return request.load;
|
|
44
|
+
};
|
|
45
|
+
var loadAndOpen = function loadAndOpen() {
|
|
46
|
+
clearPreloadTimeouts();
|
|
47
|
+
onLoad(loadReference());
|
|
48
|
+
};
|
|
49
|
+
var preloadReference = function preloadReference() {
|
|
50
|
+
if (request.preloadIntentTimeout || request.preload) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
request.preloadIntentTimeout = setTimeout(function () {
|
|
54
|
+
delete request.preloadIntentTimeout;
|
|
55
|
+
var reference = load();
|
|
56
|
+
request.preload = {
|
|
57
|
+
reference: reference,
|
|
58
|
+
dispose: function dispose() {
|
|
59
|
+
reference.dispose();
|
|
60
|
+
delete request.preload;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
request.preloadMaxAgeTimeout = setTimeout(function () {
|
|
64
|
+
var _request$preload3;
|
|
65
|
+
delete request.preloadMaxAgeTimeout;
|
|
66
|
+
(_request$preload3 = request.preload) === null || _request$preload3 === void 0 || _request$preload3.dispose();
|
|
67
|
+
}, PRELOAD_MAX_AGE);
|
|
68
|
+
}, TIME_TO_INTENT);
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
loadAndOpen: loadAndOpen,
|
|
72
|
+
preloadReference: preloadReference,
|
|
73
|
+
cancelPreload: cancelPreload
|
|
74
|
+
};
|
|
75
|
+
}, [load, onLoad]),
|
|
76
|
+
loadAndOpen = _useMemo.loadAndOpen,
|
|
77
|
+
preloadReference = _useMemo.preloadReference,
|
|
78
|
+
cancelPreload = _useMemo.cancelPreload;
|
|
79
|
+
var cleanUpEventListeners = useCallback(function () {
|
|
80
|
+
eventListeners.current.forEach(function (unbind) {
|
|
81
|
+
unbind();
|
|
82
|
+
});
|
|
83
|
+
eventListeners.current = [];
|
|
84
|
+
}, []);
|
|
85
|
+
var addEventListener = useCallback(function (element, type, callback) {
|
|
86
|
+
var unbind = bind(element, {
|
|
87
|
+
type: type,
|
|
88
|
+
listener: callback
|
|
89
|
+
});
|
|
90
|
+
eventListeners.current.push(unbind);
|
|
91
|
+
}, []);
|
|
92
|
+
var refCallback = useCallback(function (element) {
|
|
93
|
+
if (element !== nodeRef.current) {
|
|
94
|
+
if (nodeRef.current) {
|
|
95
|
+
cancelPreload();
|
|
96
|
+
cleanUpEventListeners();
|
|
97
|
+
}
|
|
98
|
+
if (element) {
|
|
99
|
+
addEventListener(element, 'mouseenter', preloadReference);
|
|
100
|
+
addEventListener(element, 'mouseleave', cancelPreload);
|
|
101
|
+
}
|
|
102
|
+
nodeRef.current = element;
|
|
103
|
+
}
|
|
104
|
+
}, [preloadReference, cancelPreload, addEventListener, cleanUpEventListeners]);
|
|
105
|
+
useEffect(function () {
|
|
106
|
+
return function () {
|
|
107
|
+
cleanUpEventListeners();
|
|
108
|
+
};
|
|
109
|
+
}, [cleanUpEventListeners]);
|
|
110
|
+
return Object.assign(refCallback, {
|
|
111
|
+
loadAndOpen: loadAndOpen
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { bind } from 'bind-event-listener';
|
|
3
|
+
export function usePressableTriggerRef(_ref) {
|
|
4
|
+
var onOpen = _ref.onOpen,
|
|
5
|
+
onClose = _ref.onClose,
|
|
6
|
+
_ref$isOpen = _ref.isOpen,
|
|
7
|
+
isOpen = _ref$isOpen === void 0 ? false : _ref$isOpen,
|
|
8
|
+
_ref$isDisabled = _ref.isDisabled,
|
|
9
|
+
isDisabled = _ref$isDisabled === void 0 ? false : _ref$isDisabled,
|
|
10
|
+
openedByRef = _ref.openedByRef;
|
|
11
|
+
var nodeRef = useRef(null);
|
|
12
|
+
var eventListeners = useRef([]);
|
|
13
|
+
var handleOpen = useCallback(function () {
|
|
14
|
+
if (isOpen) {
|
|
15
|
+
onClose === null || onClose === void 0 || onClose();
|
|
16
|
+
} else {
|
|
17
|
+
if (openedByRef) {
|
|
18
|
+
openedByRef.current = 'click';
|
|
19
|
+
}
|
|
20
|
+
onOpen();
|
|
21
|
+
}
|
|
22
|
+
}, [isOpen, onClose, openedByRef, onOpen]);
|
|
23
|
+
var keydownListener = useCallback(function (event) {
|
|
24
|
+
if (event instanceof KeyboardEvent && (event.key === 'Enter' || event.key === ' ')) {
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
handleOpen();
|
|
27
|
+
}
|
|
28
|
+
}, [handleOpen]);
|
|
29
|
+
var cleanUpEventListeners = useCallback(function () {
|
|
30
|
+
eventListeners.current.forEach(function (unbind) {
|
|
31
|
+
unbind();
|
|
32
|
+
});
|
|
33
|
+
eventListeners.current = [];
|
|
34
|
+
}, []);
|
|
35
|
+
var addEventListener = useCallback(function (element, type, callback) {
|
|
36
|
+
var unbind = bind(element, {
|
|
37
|
+
type: type,
|
|
38
|
+
listener: callback
|
|
39
|
+
});
|
|
40
|
+
eventListeners.current.push(unbind);
|
|
41
|
+
}, []);
|
|
42
|
+
var refCallback = useCallback(function (element) {
|
|
43
|
+
if (element !== nodeRef.current) {
|
|
44
|
+
if (nodeRef.current) {
|
|
45
|
+
cleanUpEventListeners();
|
|
46
|
+
}
|
|
47
|
+
if (element) {
|
|
48
|
+
if (!isDisabled) {
|
|
49
|
+
addEventListener(element, 'click', handleOpen);
|
|
50
|
+
}
|
|
51
|
+
// Always attach keydown for keyboard accessibility
|
|
52
|
+
addEventListener(element, 'keydown', keydownListener);
|
|
53
|
+
}
|
|
54
|
+
nodeRef.current = element;
|
|
55
|
+
}
|
|
56
|
+
}, [handleOpen, keydownListener, addEventListener, cleanUpEventListeners, isDisabled]);
|
|
57
|
+
useEffect(function () {
|
|
58
|
+
return function () {
|
|
59
|
+
cleanUpEventListeners();
|
|
60
|
+
};
|
|
61
|
+
}, [cleanUpEventListeners]);
|
|
62
|
+
return refCallback;
|
|
63
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if an event has a relatedTarget property.
|
|
3
|
+
*/
|
|
4
|
+
function hasRelatedTarget(event) {
|
|
5
|
+
return 'relatedTarget' in event;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Checks if the mouse is moving to an atlaskit portal or kudos modal
|
|
10
|
+
* where we should prevent the popup from closing
|
|
11
|
+
*/
|
|
12
|
+
function isMovingToKudos(relatedTarget) {
|
|
13
|
+
var _relatedTarget$closes;
|
|
14
|
+
if (!(relatedTarget instanceof HTMLElement)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
var iframe = ((_relatedTarget$closes = relatedTarget.closest('.atlaskit-portal')) === null || _relatedTarget$closes === void 0 ? void 0 : _relatedTarget$closes.querySelector('iframe')) || relatedTarget.closest('iframe');
|
|
18
|
+
return iframe instanceof HTMLIFrameElement && iframe.src.includes('give-kudos');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the child portal if mouse is moving to a portal controlled by the parent popup.
|
|
23
|
+
*/
|
|
24
|
+
function getChildPortalFromParentPopup(relatedTarget, parentPopupElement) {
|
|
25
|
+
if (!(relatedTarget instanceof HTMLElement) || !parentPopupElement) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
var portal = relatedTarget.closest('.atlaskit-portal');
|
|
29
|
+
if (!portal) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
for (var _i = 0, _Array$from = Array.from(parentPopupElement.querySelectorAll('[aria-controls]')); _i < _Array$from.length; _i++) {
|
|
33
|
+
var trigger = _Array$from[_i];
|
|
34
|
+
var controlsId = trigger.getAttribute('aria-controls');
|
|
35
|
+
if (controlsId && portal.querySelector("#".concat(controlsId))) {
|
|
36
|
+
return portal;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
export { hasRelatedTarget, isMovingToKudos, getChildPortalFromParentPopup };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
import { type ContentProps, type PopupProps, type TriggerProps } from '@atlaskit/popup';
|
|
3
|
+
import type { AnyEntryPoint, GetRuntimePropsFromEntryPoint, ParamsOfEntryPoint } from '@atlassian/entry-point-types';
|
|
4
|
+
import { type ErrorCallback, type ErrorFallback } from '@atlassian/internal-entry-point-container';
|
|
5
|
+
export type TriggerMode = 'hover' | 'click' | Array<'hover' | 'click'>;
|
|
6
|
+
type UnionOmit<T, K extends string | number | symbol> = T extends unknown ? Omit<T, K> : never;
|
|
7
|
+
type CustomPopupProps = UnionOmit<PopupProps, 'isOpen' | 'content'>;
|
|
8
|
+
type EntryPointPropsType<TEntryPoint> = GetRuntimePropsFromEntryPoint<TEntryPoint>;
|
|
9
|
+
export type PopupTriggerWithHoverProps<TEntryPoint> = {
|
|
10
|
+
entryPoint: TEntryPoint;
|
|
11
|
+
entryPointParams?: ParamsOfEntryPoint<TEntryPoint>;
|
|
12
|
+
entryPointProps?: Omit<EntryPointPropsType<TEntryPoint>, 'onClose' | 'onContentResized'> & {
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
onContentResized?: ContentProps['update'];
|
|
15
|
+
};
|
|
16
|
+
errorFallback?: ErrorFallback;
|
|
17
|
+
fallback?: ReactNode;
|
|
18
|
+
forcedReportErrorUFO?: boolean;
|
|
19
|
+
onError?: ErrorCallback;
|
|
20
|
+
onOpen?: (method: 'hover' | 'click') => void;
|
|
21
|
+
trigger: (triggerProps: TriggerProps) => ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* How the popup should be triggered. Defaults to `'click'` when omitted.
|
|
24
|
+
*/
|
|
25
|
+
triggerMode?: TriggerMode;
|
|
26
|
+
} & CustomPopupProps;
|
|
27
|
+
export declare function PopupTriggerWithHover<TEntryPoint extends AnyEntryPoint>({ trigger, triggerMode, entryPoint, entryPointParams, entryPointProps, fallback, errorFallback, onError, forcedReportErrorUFO, onOpen, onClose, ...popupProps }: PopupTriggerWithHoverProps<TEntryPoint>): React.JSX.Element;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PopupTriggerWithHover, type PopupTriggerWithHoverProps, type TriggerMode, } from './PopupTriggerWithHover';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type MutableRefObject } from 'react';
|
|
2
|
+
export type UseHoverTriggerRefProps = {
|
|
3
|
+
onOpen: () => void;
|
|
4
|
+
onClose?: () => void;
|
|
5
|
+
isOpen?: boolean;
|
|
6
|
+
isDisabled?: boolean;
|
|
7
|
+
openedByRef?: MutableRefObject<'hover' | 'click' | null>;
|
|
8
|
+
delays?: {
|
|
9
|
+
hoverOpen?: number;
|
|
10
|
+
hoverClose?: number;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Hover behavior for popup trigger and content with delayed open/close.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useHoverTriggerRef({ onOpen, onClose, isOpen, isDisabled, openedByRef, delays, }: UseHoverTriggerRefProps): {
|
|
17
|
+
triggerRef: (element: HTMLElement | null) => void;
|
|
18
|
+
contentRef: (element: HTMLElement | null) => void;
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type OnLoad<T> = (obj: {
|
|
2
|
+
dispose: () => void;
|
|
3
|
+
reference: T;
|
|
4
|
+
}) => void;
|
|
5
|
+
export type UsePreloadRefProps<T> = {
|
|
6
|
+
load: () => T;
|
|
7
|
+
onLoad: OnLoad<T>;
|
|
8
|
+
};
|
|
9
|
+
export declare function usePreloadRef<T extends {
|
|
10
|
+
dispose: () => void;
|
|
11
|
+
}>({ load, onLoad, }: UsePreloadRefProps<T>): ((element: HTMLElement | null) => void) & {
|
|
12
|
+
loadAndOpen: () => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type MutableRefObject } from 'react';
|
|
2
|
+
export type UsePressableTriggerRefProps = {
|
|
3
|
+
onOpen: () => void;
|
|
4
|
+
onClose?: () => void;
|
|
5
|
+
isOpen?: boolean;
|
|
6
|
+
isDisabled?: boolean;
|
|
7
|
+
openedByRef?: MutableRefObject<'hover' | 'click' | null>;
|
|
8
|
+
};
|
|
9
|
+
export declare function usePressableTriggerRef({ onOpen, onClose, isOpen, isDisabled, openedByRef, }: UsePressableTriggerRefProps): (element: HTMLElement | null) => void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if an event has a relatedTarget property.
|
|
3
|
+
*/
|
|
4
|
+
declare function hasRelatedTarget(event: Event): event is Event & {
|
|
5
|
+
relatedTarget: EventTarget | null;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Checks if the mouse is moving to an atlaskit portal or kudos modal
|
|
9
|
+
* where we should prevent the popup from closing
|
|
10
|
+
*/
|
|
11
|
+
declare function isMovingToKudos(relatedTarget: EventTarget | null): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the child portal if mouse is moving to a portal controlled by the parent popup.
|
|
14
|
+
*/
|
|
15
|
+
declare function getChildPortalFromParentPopup(relatedTarget: EventTarget | null, parentPopupElement: HTMLElement | null): Element | null;
|
|
16
|
+
export { hasRelatedTarget, isMovingToKudos, getChildPortalFromParentPopup };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
import { type ContentProps, type PopupProps, type TriggerProps } from '@atlaskit/popup';
|
|
3
|
+
import type { AnyEntryPoint, GetRuntimePropsFromEntryPoint, ParamsOfEntryPoint } from '@atlassian/entry-point-types';
|
|
4
|
+
import { type ErrorCallback, type ErrorFallback } from '@atlassian/internal-entry-point-container';
|
|
5
|
+
export type TriggerMode = 'hover' | 'click' | Array<'hover' | 'click'>;
|
|
6
|
+
type UnionOmit<T, K extends string | number | symbol> = T extends unknown ? Omit<T, K> : never;
|
|
7
|
+
type CustomPopupProps = UnionOmit<PopupProps, 'isOpen' | 'content'>;
|
|
8
|
+
type EntryPointPropsType<TEntryPoint> = GetRuntimePropsFromEntryPoint<TEntryPoint>;
|
|
9
|
+
export type PopupTriggerWithHoverProps<TEntryPoint> = {
|
|
10
|
+
entryPoint: TEntryPoint;
|
|
11
|
+
entryPointParams?: ParamsOfEntryPoint<TEntryPoint>;
|
|
12
|
+
entryPointProps?: Omit<EntryPointPropsType<TEntryPoint>, 'onClose' | 'onContentResized'> & {
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
onContentResized?: ContentProps['update'];
|
|
15
|
+
};
|
|
16
|
+
errorFallback?: ErrorFallback;
|
|
17
|
+
fallback?: ReactNode;
|
|
18
|
+
forcedReportErrorUFO?: boolean;
|
|
19
|
+
onError?: ErrorCallback;
|
|
20
|
+
onOpen?: (method: 'hover' | 'click') => void;
|
|
21
|
+
trigger: (triggerProps: TriggerProps) => ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* How the popup should be triggered. Defaults to `'click'` when omitted.
|
|
24
|
+
*/
|
|
25
|
+
triggerMode?: TriggerMode;
|
|
26
|
+
} & CustomPopupProps;
|
|
27
|
+
export declare function PopupTriggerWithHover<TEntryPoint extends AnyEntryPoint>({ trigger, triggerMode, entryPoint, entryPointParams, entryPointProps, fallback, errorFallback, onError, forcedReportErrorUFO, onOpen, onClose, ...popupProps }: PopupTriggerWithHoverProps<TEntryPoint>): React.JSX.Element;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PopupTriggerWithHover, type PopupTriggerWithHoverProps, type TriggerMode, } from './PopupTriggerWithHover';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type MutableRefObject } from 'react';
|
|
2
|
+
export type UseHoverTriggerRefProps = {
|
|
3
|
+
onOpen: () => void;
|
|
4
|
+
onClose?: () => void;
|
|
5
|
+
isOpen?: boolean;
|
|
6
|
+
isDisabled?: boolean;
|
|
7
|
+
openedByRef?: MutableRefObject<'hover' | 'click' | null>;
|
|
8
|
+
delays?: {
|
|
9
|
+
hoverOpen?: number;
|
|
10
|
+
hoverClose?: number;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Hover behavior for popup trigger and content with delayed open/close.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useHoverTriggerRef({ onOpen, onClose, isOpen, isDisabled, openedByRef, delays, }: UseHoverTriggerRefProps): {
|
|
17
|
+
triggerRef: (element: HTMLElement | null) => void;
|
|
18
|
+
contentRef: (element: HTMLElement | null) => void;
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type OnLoad<T> = (obj: {
|
|
2
|
+
dispose: () => void;
|
|
3
|
+
reference: T;
|
|
4
|
+
}) => void;
|
|
5
|
+
export type UsePreloadRefProps<T> = {
|
|
6
|
+
load: () => T;
|
|
7
|
+
onLoad: OnLoad<T>;
|
|
8
|
+
};
|
|
9
|
+
export declare function usePreloadRef<T extends {
|
|
10
|
+
dispose: () => void;
|
|
11
|
+
}>({ load, onLoad, }: UsePreloadRefProps<T>): ((element: HTMLElement | null) => void) & {
|
|
12
|
+
loadAndOpen: () => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type MutableRefObject } from 'react';
|
|
2
|
+
export type UsePressableTriggerRefProps = {
|
|
3
|
+
onOpen: () => void;
|
|
4
|
+
onClose?: () => void;
|
|
5
|
+
isOpen?: boolean;
|
|
6
|
+
isDisabled?: boolean;
|
|
7
|
+
openedByRef?: MutableRefObject<'hover' | 'click' | null>;
|
|
8
|
+
};
|
|
9
|
+
export declare function usePressableTriggerRef({ onOpen, onClose, isOpen, isDisabled, openedByRef, }: UsePressableTriggerRefProps): (element: HTMLElement | null) => void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if an event has a relatedTarget property.
|
|
3
|
+
*/
|
|
4
|
+
declare function hasRelatedTarget(event: Event): event is Event & {
|
|
5
|
+
relatedTarget: EventTarget | null;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Checks if the mouse is moving to an atlaskit portal or kudos modal
|
|
9
|
+
* where we should prevent the popup from closing
|
|
10
|
+
*/
|
|
11
|
+
declare function isMovingToKudos(relatedTarget: EventTarget | null): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the child portal if mouse is moving to a portal controlled by the parent popup.
|
|
14
|
+
*/
|
|
15
|
+
declare function getChildPortalFromParentPopup(relatedTarget: EventTarget | null, parentPopupElement: HTMLElement | null): Element | null;
|
|
16
|
+
export { hasRelatedTarget, isMovingToKudos, getChildPortalFromParentPopup };
|