@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.
Files changed (57) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +17 -0
  3. package/__tests__/unit/PopupTriggerWithHover.test.tsx +141 -0
  4. package/__tests__/unit/useHoverDelay.test.tsx +99 -0
  5. package/__tests__/unit/useHoverTriggerRef.test.tsx +121 -0
  6. package/__tests__/unit/usePreloadRef.test.tsx +118 -0
  7. package/__tests__/unit/usePressableTriggerRef.test.tsx +104 -0
  8. package/__tests__/unit/utils.test.tsx +86 -0
  9. package/afm-cc/tsconfig.json +40 -0
  10. package/afm-products/tsconfig.json +40 -0
  11. package/dist/cjs/PopupTriggerWithHover.js +158 -0
  12. package/dist/cjs/index.js +12 -0
  13. package/dist/cjs/useHoverDelay.js +38 -0
  14. package/dist/cjs/useHoverTriggerRef.js +155 -0
  15. package/dist/cjs/usePreloadRef.js +119 -0
  16. package/dist/cjs/usePressableTriggerRef.js +69 -0
  17. package/dist/cjs/utils.js +48 -0
  18. package/dist/es2019/PopupTriggerWithHover.js +139 -0
  19. package/dist/es2019/index.js +1 -0
  20. package/dist/es2019/useHoverDelay.js +32 -0
  21. package/dist/es2019/useHoverTriggerRef.js +139 -0
  22. package/dist/es2019/usePreloadRef.js +115 -0
  23. package/dist/es2019/usePressableTriggerRef.js +62 -0
  24. package/dist/es2019/utils.js +40 -0
  25. package/dist/esm/PopupTriggerWithHover.js +149 -0
  26. package/dist/esm/index.js +1 -0
  27. package/dist/esm/useHoverDelay.js +34 -0
  28. package/dist/esm/useHoverTriggerRef.js +149 -0
  29. package/dist/esm/usePreloadRef.js +113 -0
  30. package/dist/esm/usePressableTriggerRef.js +63 -0
  31. package/dist/esm/utils.js +41 -0
  32. package/dist/types/PopupTriggerWithHover.d.ts +28 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/types/useHoverDelay.d.ts +8 -0
  35. package/dist/types/useHoverTriggerRef.d.ts +19 -0
  36. package/dist/types/usePreloadRef.d.ts +13 -0
  37. package/dist/types/usePressableTriggerRef.d.ts +9 -0
  38. package/dist/types/utils.d.ts +16 -0
  39. package/dist/types-ts4.5/PopupTriggerWithHover.d.ts +28 -0
  40. package/dist/types-ts4.5/index.d.ts +1 -0
  41. package/dist/types-ts4.5/useHoverDelay.d.ts +8 -0
  42. package/dist/types-ts4.5/useHoverTriggerRef.d.ts +19 -0
  43. package/dist/types-ts4.5/usePreloadRef.d.ts +13 -0
  44. package/dist/types-ts4.5/usePressableTriggerRef.d.ts +9 -0
  45. package/dist/types-ts4.5/utils.d.ts +16 -0
  46. package/package.json +81 -0
  47. package/popup-trigger-with-hover/package.json +17 -0
  48. package/src/PopupTriggerWithHover.tsx +240 -0
  49. package/src/index.ts +5 -0
  50. package/src/useHoverDelay.ts +42 -0
  51. package/src/useHoverTriggerRef.ts +177 -0
  52. package/src/usePreloadRef.ts +152 -0
  53. package/src/usePressableTriggerRef.ts +89 -0
  54. package/src/utils.ts +49 -0
  55. package/tsconfig.app.json +46 -0
  56. package/tsconfig.dev.json +45 -0
  57. 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,8 @@
1
+ /**
2
+ * Hook for managing delayed hover actions with timeout management.
3
+ */
4
+ declare function useHoverDelay(callback: () => void, delay: number): {
5
+ schedule: () => void;
6
+ clear: () => void;
7
+ };
8
+ export { useHoverDelay };
@@ -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,8 @@
1
+ /**
2
+ * Hook for managing delayed hover actions with timeout management.
3
+ */
4
+ declare function useHoverDelay(callback: () => void, delay: number): {
5
+ schedule: () => void;
6
+ clear: () => void;
7
+ };
8
+ export { useHoverDelay };
@@ -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 };