@vuu-ui/vuu-popups 2.1.18 → 2.1.19-beta.2
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/package.json +10 -13
- package/src/index.js +4 -0
- package/src/popup/Popup.js +29 -0
- package/src/popup/getPositionRelativeToAnchor.js +47 -0
- package/src/popup/index.js +2 -0
- package/src/popup/useAnchoredPosition.js +41 -0
- package/src/popup-menu/PopupMenu.css.js +11 -0
- package/src/popup-menu/PopupMenu.js +67 -0
- package/src/popup-menu/index.js +1 -0
- package/src/popup-menu/usePopupMenu.js +72 -0
- package/src/portal/Portal.css.js +27 -0
- package/src/portal/Portal.js +62 -0
- package/src/portal/index.js +1 -0
- package/src/tooltip/Tooltip.css.js +76 -0
- package/src/tooltip/Tooltip.js +41 -0
- package/src/tooltip/index.js +2 -0
- package/src/tooltip/useTooltip.js +91 -0
- package/src/tooltip/useTooltipAnchoredPosition.js +102 -0
- package/cjs/index.js +0 -18
- package/cjs/index.js.map +0 -1
- package/cjs/popup/Popup.css.js +0 -6
- package/cjs/popup/Popup.css.js.map +0 -1
- package/cjs/popup/Popup.js +0 -38
- package/cjs/popup/Popup.js.map +0 -1
- package/cjs/popup/getPositionRelativeToAnchor.js +0 -43
- package/cjs/popup/getPositionRelativeToAnchor.js.map +0 -1
- package/cjs/popup/useAnchoredPosition.js +0 -58
- package/cjs/popup/useAnchoredPosition.js.map +0 -1
- package/cjs/popup-menu/PopupMenu.css.js +0 -6
- package/cjs/popup-menu/PopupMenu.css.js.map +0 -1
- package/cjs/popup-menu/PopupMenu.js +0 -100
- package/cjs/popup-menu/PopupMenu.js.map +0 -1
- package/cjs/popup-menu/usePopupMenu.js +0 -100
- package/cjs/popup-menu/usePopupMenu.js.map +0 -1
- package/cjs/portal/Portal.css.js +0 -6
- package/cjs/portal/Portal.css.js.map +0 -1
- package/cjs/portal/Portal.js +0 -73
- package/cjs/portal/Portal.js.map +0 -1
- package/cjs/tooltip/Tooltip.css.js +0 -6
- package/cjs/tooltip/Tooltip.css.js.map +0 -1
- package/cjs/tooltip/Tooltip.js +0 -56
- package/cjs/tooltip/Tooltip.js.map +0 -1
- package/cjs/tooltip/useTooltip.js +0 -106
- package/cjs/tooltip/useTooltip.js.map +0 -1
- package/cjs/tooltip/useTooltipAnchoredPosition.js +0 -117
- package/cjs/tooltip/useTooltipAnchoredPosition.js.map +0 -1
- package/esm/index.js +0 -7
- package/esm/index.js.map +0 -1
- package/esm/popup/Popup.css.js +0 -4
- package/esm/popup/Popup.css.js.map +0 -1
- package/esm/popup/Popup.js +0 -36
- package/esm/popup/Popup.js.map +0 -1
- package/esm/popup/getPositionRelativeToAnchor.js +0 -41
- package/esm/popup/getPositionRelativeToAnchor.js.map +0 -1
- package/esm/popup/useAnchoredPosition.js +0 -56
- package/esm/popup/useAnchoredPosition.js.map +0 -1
- package/esm/popup-menu/PopupMenu.css.js +0 -4
- package/esm/popup-menu/PopupMenu.css.js.map +0 -1
- package/esm/popup-menu/PopupMenu.js +0 -98
- package/esm/popup-menu/PopupMenu.js.map +0 -1
- package/esm/popup-menu/usePopupMenu.js +0 -98
- package/esm/popup-menu/usePopupMenu.js.map +0 -1
- package/esm/portal/Portal.css.js +0 -4
- package/esm/portal/Portal.css.js.map +0 -1
- package/esm/portal/Portal.js +0 -71
- package/esm/portal/Portal.js.map +0 -1
- package/esm/tooltip/Tooltip.css.js +0 -4
- package/esm/tooltip/Tooltip.css.js.map +0 -1
- package/esm/tooltip/Tooltip.js +0 -54
- package/esm/tooltip/Tooltip.js.map +0 -1
- package/esm/tooltip/useTooltip.js +0 -104
- package/esm/tooltip/useTooltip.js.map +0 -1
- package/esm/tooltip/useTooltipAnchoredPosition.js +0 -115
- package/esm/tooltip/useTooltipAnchoredPosition.js.map +0 -1
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { getPositionRelativeToAnchor } from '../popup/getPositionRelativeToAnchor.js';
|
|
3
|
-
import { useContextMenu } from '@vuu-ui/vuu-context-menu';
|
|
4
|
-
|
|
5
|
-
const usePopupMenu = ({
|
|
6
|
-
anchorElement,
|
|
7
|
-
"aria-label": ariaLabel = "Popup menu",
|
|
8
|
-
id,
|
|
9
|
-
menuActionHandler,
|
|
10
|
-
menuBuilder,
|
|
11
|
-
menuLocation,
|
|
12
|
-
menuOptions,
|
|
13
|
-
onMenuClose,
|
|
14
|
-
onMenuOpen,
|
|
15
|
-
popupPlacement,
|
|
16
|
-
tabIndex
|
|
17
|
-
}) => {
|
|
18
|
-
const [menuOpen, _setMenuOpen] = useState(false);
|
|
19
|
-
const suppressShowMenuRef = useRef(false);
|
|
20
|
-
const rootRef = useRef(null);
|
|
21
|
-
const setMenuOpen = useCallback(
|
|
22
|
-
(isOpen) => {
|
|
23
|
-
_setMenuOpen(isOpen);
|
|
24
|
-
if (isOpen) {
|
|
25
|
-
onMenuOpen?.();
|
|
26
|
-
setTimeout(() => {
|
|
27
|
-
const firstOption = document.activeElement?.querySelector(
|
|
28
|
-
".saltMenuItem"
|
|
29
|
-
);
|
|
30
|
-
firstOption?.focus();
|
|
31
|
-
}, 40);
|
|
32
|
-
} else {
|
|
33
|
-
suppressShowMenuRef.current = false;
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
[onMenuOpen]
|
|
37
|
-
);
|
|
38
|
-
const showContextMenu = useContextMenu(menuBuilder, menuActionHandler);
|
|
39
|
-
const handleMenuOpenChange = useCallback(
|
|
40
|
-
(isOpen) => {
|
|
41
|
-
if (!isOpen) {
|
|
42
|
-
setMenuOpen(false);
|
|
43
|
-
onMenuClose?.();
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
[onMenuClose, setMenuOpen]
|
|
47
|
-
);
|
|
48
|
-
const showMenu = useCallback(
|
|
49
|
-
(e) => {
|
|
50
|
-
if (suppressShowMenuRef.current) {
|
|
51
|
-
suppressShowMenuRef.current = false;
|
|
52
|
-
} else {
|
|
53
|
-
suppressShowMenuRef.current = true;
|
|
54
|
-
const anchorEl = anchorElement?.current ?? rootRef.current;
|
|
55
|
-
if (anchorEl) {
|
|
56
|
-
const {
|
|
57
|
-
left: x,
|
|
58
|
-
top: y
|
|
59
|
-
// width,
|
|
60
|
-
} = getPositionRelativeToAnchor(anchorEl, popupPlacement, 0, 0);
|
|
61
|
-
setMenuOpen(true);
|
|
62
|
-
showContextMenu(e, menuLocation, menuOptions, {
|
|
63
|
-
// className: menuClassName,
|
|
64
|
-
// id: `${id}-menu`,
|
|
65
|
-
onOpenChange: handleMenuOpenChange,
|
|
66
|
-
x,
|
|
67
|
-
y
|
|
68
|
-
// style: { width: width ? width - 2 : undefined },
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
[
|
|
74
|
-
anchorElement,
|
|
75
|
-
popupPlacement,
|
|
76
|
-
setMenuOpen,
|
|
77
|
-
showContextMenu,
|
|
78
|
-
menuLocation,
|
|
79
|
-
menuOptions,
|
|
80
|
-
handleMenuOpenChange
|
|
81
|
-
]
|
|
82
|
-
);
|
|
83
|
-
const ariaAttributes = {
|
|
84
|
-
"aria-controls": menuOpen ? `${id}-menu` : void 0,
|
|
85
|
-
"aria-label": ariaLabel,
|
|
86
|
-
"aria-expanded": menuOpen,
|
|
87
|
-
"aria-haspopup": "menu"
|
|
88
|
-
};
|
|
89
|
-
const buttonProps = {
|
|
90
|
-
id,
|
|
91
|
-
onClick: showMenu,
|
|
92
|
-
tabIndex
|
|
93
|
-
};
|
|
94
|
-
return { ariaAttributes, buttonProps, menuOpen, rootRef };
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export { usePopupMenu };
|
|
98
|
-
//# sourceMappingURL=usePopupMenu.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"usePopupMenu.js","sources":["../../../../packages/vuu-popups/src/popup-menu/usePopupMenu.ts"],"sourcesContent":["import {\n AriaAttributes,\n MouseEvent,\n useCallback,\n useRef,\n useState,\n} from \"react\";\nimport { PopupMenuProps } from \"./PopupMenu\";\nimport { getPositionRelativeToAnchor } from \"../popup/getPositionRelativeToAnchor\";\nimport { PopupPlacement } from \"../popup/Popup\";\nimport { useContextMenu } from \"@vuu-ui/vuu-context-menu\";\n\nexport interface PopupMenuHookProps\n extends Pick<\n PopupMenuProps,\n | \"anchorElement\"\n | \"aria-label\"\n | \"menuActionHandler\"\n | \"menuBuilder\"\n | \"menuClassName\"\n | \"menuOptions\"\n | \"onMenuClose\"\n | \"onMenuOpen\"\n > {\n id: string;\n menuLocation: string;\n popupPlacement: PopupPlacement;\n tabIndex: number;\n}\n\nexport const usePopupMenu = ({\n anchorElement,\n \"aria-label\": ariaLabel = \"Popup menu\",\n id,\n menuActionHandler,\n menuBuilder,\n menuLocation,\n menuOptions,\n onMenuClose,\n onMenuOpen,\n popupPlacement,\n tabIndex,\n}: PopupMenuHookProps) => {\n const [menuOpen, _setMenuOpen] = useState(false);\n const suppressShowMenuRef = useRef(false);\n const rootRef = useRef<HTMLButtonElement>(null);\n\n const setMenuOpen = useCallback(\n (isOpen: boolean) => {\n _setMenuOpen(isOpen);\n if (isOpen) {\n onMenuOpen?.();\n setTimeout(() => {\n const firstOption = document.activeElement?.querySelector(\n \".saltMenuItem\",\n ) as HTMLElement;\n firstOption?.focus();\n }, 40);\n } else {\n suppressShowMenuRef.current = false;\n }\n },\n [onMenuOpen],\n );\n\n const showContextMenu = useContextMenu(menuBuilder, menuActionHandler);\n\n const handleMenuOpenChange = useCallback(\n (isOpen: boolean) => {\n if (!isOpen) {\n setMenuOpen(false);\n onMenuClose?.();\n }\n },\n [onMenuClose, setMenuOpen],\n );\n\n const showMenu = useCallback(\n (e: MouseEvent<HTMLElement>) => {\n if (suppressShowMenuRef.current) {\n suppressShowMenuRef.current = false;\n } else {\n suppressShowMenuRef.current = true;\n const anchorEl = anchorElement?.current ?? rootRef.current;\n if (anchorEl) {\n const {\n left: x,\n top: y,\n // width,\n } = getPositionRelativeToAnchor(anchorEl, popupPlacement, 0, 0);\n setMenuOpen(true);\n\n showContextMenu(e, menuLocation, menuOptions, {\n // className: menuClassName,\n // id: `${id}-menu`,\n onOpenChange: handleMenuOpenChange,\n x,\n y,\n // style: { width: width ? width - 2 : undefined },\n });\n }\n }\n },\n [\n anchorElement,\n popupPlacement,\n setMenuOpen,\n showContextMenu,\n menuLocation,\n menuOptions,\n handleMenuOpenChange,\n ],\n );\n\n const ariaAttributes: AriaAttributes = {\n \"aria-controls\": menuOpen ? `${id}-menu` : undefined,\n \"aria-label\": ariaLabel,\n \"aria-expanded\": menuOpen,\n \"aria-haspopup\": \"menu\",\n };\n\n const buttonProps = {\n id,\n onClick: showMenu,\n tabIndex,\n };\n\n return { ariaAttributes, buttonProps, menuOpen, rootRef };\n};\n"],"names":[],"mappings":"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"}
|
package/esm/portal/Portal.css.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
var portalCss = "/*\nThere is work to do to sort out styling across Portal/Popup/Draggable\n*/\n.vuuPortal {\n position: absolute;\n z-index: 100;\n}\n\n.vuuPortal:not(.vuuPopup) {\n background-color: var(--salt-container-primary-background);\n border-radius:4px;\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n border-color: var(--vuuMenuList-borderColor, var(--salt-container-primary-borderColor));\n border-style: solid;\n border-width: 1px;\n padding: 4px 0;\n}\n\n.vuuPortal:has(.vuuDropdown-popup-component.vuuList-empty){\n display: none;\n}\n\n#vuu-portal-root {\n z-index: 1000;\n}";
|
|
2
|
-
|
|
3
|
-
export { portalCss as default };
|
|
4
|
-
//# sourceMappingURL=Portal.css.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Portal.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
package/esm/portal/Portal.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { useThemeAttributes } from '@vuu-ui/vuu-utils';
|
|
2
|
-
import { useState, useRef, useLayoutEffect } from 'react';
|
|
3
|
-
import { createPortal } from 'react-dom';
|
|
4
|
-
import { useComponentCssInjection } from '@salt-ds/styles';
|
|
5
|
-
import { useWindow } from '@salt-ds/window';
|
|
6
|
-
import portalCss from './Portal.css.js';
|
|
7
|
-
|
|
8
|
-
function getContainer(container) {
|
|
9
|
-
return typeof container === "function" ? container() : container;
|
|
10
|
-
}
|
|
11
|
-
const DEFAULT_ID = ["vuu-dialog-portal-root", "vuu-portal-root"];
|
|
12
|
-
const getFirstAvailableElementById = (id) => {
|
|
13
|
-
if (Array.isArray(id)) {
|
|
14
|
-
for (const i of id) {
|
|
15
|
-
const element = document.getElementById(i);
|
|
16
|
-
if (element) {
|
|
17
|
-
return element;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
} else {
|
|
21
|
-
return document.getElementById(id);
|
|
22
|
-
}
|
|
23
|
-
return null;
|
|
24
|
-
};
|
|
25
|
-
const Portal = ({
|
|
26
|
-
children,
|
|
27
|
-
container: containerProp = document.body,
|
|
28
|
-
id = DEFAULT_ID,
|
|
29
|
-
onRender,
|
|
30
|
-
open = true,
|
|
31
|
-
themeAttributes
|
|
32
|
-
}) => {
|
|
33
|
-
const targetWindow = useWindow();
|
|
34
|
-
useComponentCssInjection({
|
|
35
|
-
testId: "vuu-portal",
|
|
36
|
-
css: portalCss,
|
|
37
|
-
window: targetWindow
|
|
38
|
-
});
|
|
39
|
-
const [mounted, setMounted] = useState(false);
|
|
40
|
-
const portalRef = useRef(null);
|
|
41
|
-
const container = getContainer(containerProp) ?? document.body;
|
|
42
|
-
const [themeClass, densityClass, dataMode] = useThemeAttributes(themeAttributes);
|
|
43
|
-
useLayoutEffect(() => {
|
|
44
|
-
const root = getFirstAvailableElementById(id);
|
|
45
|
-
if (root) {
|
|
46
|
-
portalRef.current = root;
|
|
47
|
-
} else {
|
|
48
|
-
portalRef.current = document.createElement("div");
|
|
49
|
-
portalRef.current.id = typeof id === "string" ? id : id.length > 0 ? id.at(-1) : "vuu-portal-root";
|
|
50
|
-
}
|
|
51
|
-
const el = portalRef.current;
|
|
52
|
-
if (!container.contains(el)) {
|
|
53
|
-
container.appendChild(el);
|
|
54
|
-
}
|
|
55
|
-
el.classList.add(themeClass, densityClass);
|
|
56
|
-
el.dataset.mode = dataMode;
|
|
57
|
-
setMounted(true);
|
|
58
|
-
}, [id, container, themeClass, densityClass, dataMode]);
|
|
59
|
-
useLayoutEffect(() => {
|
|
60
|
-
requestAnimationFrame(() => {
|
|
61
|
-
onRender?.();
|
|
62
|
-
});
|
|
63
|
-
}, [onRender]);
|
|
64
|
-
if (open && mounted && portalRef.current && children) {
|
|
65
|
-
return createPortal(children, portalRef.current);
|
|
66
|
-
}
|
|
67
|
-
return null;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export { Portal };
|
|
71
|
-
//# sourceMappingURL=Portal.js.map
|
package/esm/portal/Portal.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Portal.js","sources":["../../../../packages/vuu-popups/src/portal/Portal.tsx"],"sourcesContent":["import { ThemeAttributes, useThemeAttributes } from \"@vuu-ui/vuu-utils\";\nimport { ReactNode, useLayoutEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\n\nimport portalCss from \"./Portal.css\";\n\nexport interface PortalProps {\n /**\n * The children to render into the `container`.\n */\n children?: ReactNode;\n /**\n * An HTML element, component instance, or function that returns either.\n * The `container` will have the portal children appended to it.\n *\n * By default, it uses the body of the top-level document object,\n * so it's simply `document.body` most of the time.\n */\n container?: Element | (() => Element | null) | null;\n /**\n * Id of element into which portal will be rendered. If this node does not exist on the document,\n * it will be created for you. If more than one value is provided, the first element found will\n * be used.\n */\n id?: string | string[];\n /**\n * Callback invoked immediately after render (in layoutEffect). Can be\n * used to check position vis-a-vis viewport and adjust if out of bounds\n */\n onRender?: () => void;\n /**\n * Allow conditional rendering of this Portal, if false, will render nothing.\n * Defaults to true\n */\n open?: boolean;\n /**\n * ThemeAttributes can be passed in for cases where ContextMenu is\n * rendered via popup-service showPopup, outside the Context hierarchy.\n */\n themeAttributes?: ThemeAttributes;\n}\n\nfunction getContainer(container: PortalProps[\"container\"]) {\n return typeof container === \"function\" ? container() : container;\n}\n\nconst DEFAULT_ID = [\"vuu-dialog-portal-root\", \"vuu-portal-root\"];\n\nconst getFirstAvailableElementById = (id: string | string[]) => {\n if (Array.isArray(id)) {\n for (const i of id) {\n const element = document.getElementById(i);\n if (element) {\n return element;\n }\n }\n } else {\n return document.getElementById(id);\n }\n return null;\n};\n\n/**\n * Portals provide a first-class way to render children into a DOM node\n * that exists outside the DOM hierarchy of the parent component.\n */\nexport const Portal = ({\n children,\n container: containerProp = document.body,\n id = DEFAULT_ID,\n onRender,\n open = true,\n themeAttributes,\n}: PortalProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-portal\",\n css: portalCss,\n window: targetWindow,\n });\n\n const [mounted, setMounted] = useState(false);\n const portalRef = useRef<HTMLElement | null>(null);\n const container = getContainer(containerProp) ?? document.body;\n const [themeClass, densityClass, dataMode] =\n useThemeAttributes(themeAttributes);\n\n useLayoutEffect(() => {\n const root = getFirstAvailableElementById(id);\n if (root) {\n portalRef.current = root;\n } else {\n portalRef.current = document.createElement(\"div\");\n portalRef.current.id =\n typeof id === \"string\"\n ? id\n : id.length > 0\n ? (id.at(-1) as string)\n : \"vuu-portal-root\";\n }\n const el = portalRef.current;\n if (!container.contains(el)) {\n container.appendChild(el);\n }\n el.classList.add(themeClass, densityClass);\n el.dataset.mode = dataMode;\n setMounted(true);\n }, [id, container, themeClass, densityClass, dataMode]);\n\n useLayoutEffect(() => {\n requestAnimationFrame(() => {\n onRender?.();\n });\n }, [onRender]);\n\n if (open && mounted && portalRef.current && children) {\n return createPortal(children, portalRef.current);\n }\n\n return null;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
var tooltipCss = ".vuuTooltip {\n --tooltip-align: flex-start;\n --tooltip-background: var(--salt-actionable-bold-background-hover);\n --tooltip-border: var(--salt-actionable-bold-background-hover);\n --tooltip-color: var(--salt-actionable-bold-foreground-hover);\n --tooltip-justify: flex-start;\n --tooltip-top: auto;\n --tooltip-right: auto;\n --tooltip-bottom: auto;\n --tooltip-left: auto;\n align-items: var(--tooltip-align);\n justify-content: var(--tooltip-justify);\n display: flex;\n position: absolute;\n transition: opacity 0.15s ease-in;\n z-index: 100;\n\n &.vuuHidden {\n opacity: 0;\n }\n}\n\n.vuuTooltip-content {\n background-color: var(--tooltip-background);\n border-color: var(--tooltip-border);\n border-width: 1px;\n border-style: solid;\n border-radius: var(--vuuTooltip-borderRadius, 6px);\n box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);\n color: var(--tooltip-color);\n line-height: 24px;\n padding: 2px 8px;\n white-space: nowrap;\n}\n\n.vuuTooltip::before {\n background-color: var(--tooltip-border);\n content: \" \";\n display: block;\n position: absolute;\n transform: rotate(45deg);\n width: 12px;\n height: 12px;\n z-index: -1;\n}\n\n.vuuTooltip[data-align=\"above\"]:before {\n bottom: -6px;\n left: calc(50% - 6px);\n}\n\n.vuuTooltip[data-align=\"below\"]:before {\n top: -6px;\n left: calc(50% - 6px);\n}\n\n.vuuTooltip[data-align=\"right\"]:before {\n left: -6px;\n top: calc(50% - 6px);\n}\n\n.vuuTooltip[data-align=\"left\"]:before {\n right: -6px;\n top: calc(50% - 6px);\n}\n\n.vuuTooltip-error {\n --tooltip-background: var(--vuu-color-red-50);\n --tooltip-color: white;\n color: white;\n}\n";
|
|
2
|
-
|
|
3
|
-
export { tooltipCss as default };
|
|
4
|
-
//# sourceMappingURL=Tooltip.css.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
package/esm/tooltip/Tooltip.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { Portal } from '../portal/Portal.js';
|
|
3
|
-
import { useTooltipAnchoredPosition } from './useTooltipAnchoredPosition.js';
|
|
4
|
-
import cx from 'clsx';
|
|
5
|
-
import { useComponentCssInjection } from '@salt-ds/styles';
|
|
6
|
-
import { useWindow } from '@salt-ds/window';
|
|
7
|
-
import tooltipCss from './Tooltip.css.js';
|
|
8
|
-
|
|
9
|
-
const classBase = "vuuTooltip";
|
|
10
|
-
const Tooltip = ({
|
|
11
|
-
anchorElement,
|
|
12
|
-
children,
|
|
13
|
-
className,
|
|
14
|
-
id,
|
|
15
|
-
onMouseEnter,
|
|
16
|
-
onMouseLeave,
|
|
17
|
-
placement: placementProp,
|
|
18
|
-
status,
|
|
19
|
-
style: styleProp
|
|
20
|
-
}) => {
|
|
21
|
-
const targetWindow = useWindow();
|
|
22
|
-
useComponentCssInjection({
|
|
23
|
-
testId: "vuu-tooltip",
|
|
24
|
-
css: tooltipCss,
|
|
25
|
-
window: targetWindow
|
|
26
|
-
});
|
|
27
|
-
const ref = useTooltipAnchoredPosition({
|
|
28
|
-
anchorElement,
|
|
29
|
-
placement: placementProp
|
|
30
|
-
});
|
|
31
|
-
return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
|
|
32
|
-
"div",
|
|
33
|
-
{
|
|
34
|
-
className: cx(classBase, className, "vuuHidden", {
|
|
35
|
-
[`${classBase}-error`]: status === "error"
|
|
36
|
-
}),
|
|
37
|
-
id,
|
|
38
|
-
ref,
|
|
39
|
-
style: { ...styleProp, left: 0, top: 0 },
|
|
40
|
-
children: /* @__PURE__ */ jsx(
|
|
41
|
-
"span",
|
|
42
|
-
{
|
|
43
|
-
className: `${classBase}-content`,
|
|
44
|
-
onMouseEnter,
|
|
45
|
-
onMouseLeave,
|
|
46
|
-
children
|
|
47
|
-
}
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
) });
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export { Tooltip };
|
|
54
|
-
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.js","sources":["../../../../packages/vuu-popups/src/tooltip/Tooltip.tsx"],"sourcesContent":["import { CSSProperties, MouseEventHandler, ReactNode, RefObject } from \"react\";\nimport { Portal } from \"../portal\";\nimport {\n TooltipPlacement,\n useTooltipAnchoredPosition,\n} from \"./useTooltipAnchoredPosition\";\nimport cx from \"clsx\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\n\nimport tooltipCss from \"./Tooltip.css\";\n\nconst classBase = \"vuuTooltip\";\n\nexport type TooltipStatus = \"warning\" | \"error\" | \"info\";\nexport interface TooltipProps {\n anchorElement: RefObject<HTMLElement | null>;\n children: ReactNode;\n className?: string;\n id?: string;\n onMouseEnter: MouseEventHandler;\n onMouseLeave: MouseEventHandler;\n placement: TooltipPlacement | TooltipPlacement[];\n status?: TooltipStatus;\n style?: CSSProperties;\n}\n\nexport const Tooltip = ({\n anchorElement,\n children,\n className,\n id,\n onMouseEnter,\n onMouseLeave,\n placement: placementProp,\n status,\n style: styleProp,\n}: TooltipProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-tooltip\",\n css: tooltipCss,\n window: targetWindow,\n });\n\n const ref = useTooltipAnchoredPosition({\n anchorElement,\n placement: placementProp,\n });\n return (\n <Portal>\n <div\n className={cx(classBase, className, \"vuuHidden\", {\n [`${classBase}-error`]: status === \"error\",\n })}\n id={id}\n ref={ref}\n style={{ ...styleProp, left: 0, top: 0 }}\n >\n <span\n className={`${classBase}-content`}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n >\n {children}\n </span>\n </div>\n </Portal>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAYA,MAAM,SAAY,GAAA,YAAA;AAeX,MAAM,UAAU,CAAC;AAAA,EACtB,aAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,EAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAW,EAAA,aAAA;AAAA,EACX,MAAA;AAAA,EACA,KAAO,EAAA;AACT,CAAoB,KAAA;AAClB,EAAA,MAAM,eAAe,SAAU,EAAA;AAC/B,EAAyB,wBAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,aAAA;AAAA,IACR,GAAK,EAAA,UAAA;AAAA,IACL,MAAQ,EAAA;AAAA,GACT,CAAA;AAED,EAAA,MAAM,MAAM,0BAA2B,CAAA;AAAA,IACrC,aAAA;AAAA,IACA,SAAW,EAAA;AAAA,GACZ,CAAA;AACD,EAAA,2BACG,MACC,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAW,EAAA,EAAA,CAAG,SAAW,EAAA,SAAA,EAAW,WAAa,EAAA;AAAA,QAC/C,CAAC,CAAA,EAAG,SAAS,CAAA,MAAA,CAAQ,GAAG,MAAW,KAAA;AAAA,OACpC,CAAA;AAAA,MACD,EAAA;AAAA,MACA,GAAA;AAAA,MACA,OAAO,EAAE,GAAG,WAAW,IAAM,EAAA,CAAA,EAAG,KAAK,CAAE,EAAA;AAAA,MAEvC,QAAA,kBAAA,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAW,GAAG,SAAS,CAAA,QAAA,CAAA;AAAA,UACvB,YAAA;AAAA,UACA,YAAA;AAAA,UAEC;AAAA;AAAA;AACH;AAAA,GAEJ,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { useId, queryClosest } from '@vuu-ui/vuu-utils';
|
|
2
|
-
import { useRef, useState, useCallback } from 'react';
|
|
3
|
-
|
|
4
|
-
const useTooltip = ({
|
|
5
|
-
anchorQuery = "*",
|
|
6
|
-
id: idProp,
|
|
7
|
-
placement = ["right", "above", "below"],
|
|
8
|
-
tooltipContent
|
|
9
|
-
}) => {
|
|
10
|
-
const hideTooltipRef = useRef(void 0);
|
|
11
|
-
const isHoveringRef = useRef(false);
|
|
12
|
-
const anchorElementRef = useRef(null);
|
|
13
|
-
const mouseEnterTimerRef = useRef(void 0);
|
|
14
|
-
const mouseLeaveTimerRef = useRef(void 0);
|
|
15
|
-
const [tooltipProps, setTooltipProps] = useState();
|
|
16
|
-
const id = useId(idProp);
|
|
17
|
-
const escapeListener = useCallback((evt) => {
|
|
18
|
-
if (evt.key === "Escape") {
|
|
19
|
-
hideTooltipRef.current?.();
|
|
20
|
-
}
|
|
21
|
-
}, []);
|
|
22
|
-
hideTooltipRef.current = useCallback(() => {
|
|
23
|
-
setTooltipProps(void 0);
|
|
24
|
-
document.removeEventListener("keydown", escapeListener);
|
|
25
|
-
}, [escapeListener]);
|
|
26
|
-
const handleMouseEnterTooltip = useCallback(() => {
|
|
27
|
-
window.clearTimeout(mouseLeaveTimerRef.current);
|
|
28
|
-
}, []);
|
|
29
|
-
const handleMouseLeaveTooltip = useCallback(() => {
|
|
30
|
-
hideTooltipRef.current?.();
|
|
31
|
-
}, []);
|
|
32
|
-
const hideTooltip = useCallback((defer = 0) => {
|
|
33
|
-
if (mouseEnterTimerRef.current) {
|
|
34
|
-
window.clearTimeout(mouseEnterTimerRef.current);
|
|
35
|
-
mouseEnterTimerRef.current = void 0;
|
|
36
|
-
} else if (hideTooltipRef.current) {
|
|
37
|
-
if (defer === 0) {
|
|
38
|
-
hideTooltipRef.current();
|
|
39
|
-
} else {
|
|
40
|
-
mouseLeaveTimerRef.current = window.setTimeout(
|
|
41
|
-
hideTooltipRef.current,
|
|
42
|
-
defer
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}, []);
|
|
47
|
-
const showTooltip = useCallback(
|
|
48
|
-
(ref = anchorElementRef) => {
|
|
49
|
-
const { current: anchorEl } = ref;
|
|
50
|
-
if (anchorEl) {
|
|
51
|
-
setTooltipProps({
|
|
52
|
-
anchorElement: ref,
|
|
53
|
-
children: tooltipContent,
|
|
54
|
-
id: `${id}-tooltip`,
|
|
55
|
-
onMouseEnter: handleMouseEnterTooltip,
|
|
56
|
-
onMouseLeave: handleMouseLeaveTooltip,
|
|
57
|
-
placement
|
|
58
|
-
});
|
|
59
|
-
document.addEventListener("keydown", escapeListener);
|
|
60
|
-
}
|
|
61
|
-
mouseEnterTimerRef.current = void 0;
|
|
62
|
-
hideTooltip(isHoveringRef.current ? 3e3 : 1e3);
|
|
63
|
-
},
|
|
64
|
-
[
|
|
65
|
-
escapeListener,
|
|
66
|
-
handleMouseEnterTooltip,
|
|
67
|
-
handleMouseLeaveTooltip,
|
|
68
|
-
hideTooltip,
|
|
69
|
-
id,
|
|
70
|
-
placement,
|
|
71
|
-
tooltipContent
|
|
72
|
-
]
|
|
73
|
-
);
|
|
74
|
-
const handleMouseEnter = useCallback(
|
|
75
|
-
(evt) => {
|
|
76
|
-
isHoveringRef.current = true;
|
|
77
|
-
const el = queryClosest(evt.target, anchorQuery);
|
|
78
|
-
if (el) {
|
|
79
|
-
console.log(`el ${el.classList}`);
|
|
80
|
-
anchorElementRef.current = el;
|
|
81
|
-
mouseEnterTimerRef.current = window.setTimeout(showTooltip, 800);
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
[anchorQuery, showTooltip]
|
|
85
|
-
);
|
|
86
|
-
const handleMouseLeave = useCallback(() => {
|
|
87
|
-
isHoveringRef.current = false;
|
|
88
|
-
hideTooltip(200);
|
|
89
|
-
}, [hideTooltip]);
|
|
90
|
-
const anchorProps = {
|
|
91
|
-
"aria-describedby": `${id}-tooltip`,
|
|
92
|
-
onMouseEnter: handleMouseEnter,
|
|
93
|
-
onMouseLeave: handleMouseLeave
|
|
94
|
-
};
|
|
95
|
-
return {
|
|
96
|
-
anchorProps,
|
|
97
|
-
hideTooltip,
|
|
98
|
-
showTooltip,
|
|
99
|
-
tooltipProps
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export { useTooltip };
|
|
104
|
-
//# sourceMappingURL=useTooltip.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTooltip.js","sources":["../../../../packages/vuu-popups/src/tooltip/useTooltip.ts"],"sourcesContent":["import { queryClosest, useId } from \"@vuu-ui/vuu-utils\";\nimport { MouseEvent, ReactNode, useCallback, useRef, useState } from \"react\";\nimport { TooltipProps } from \"./Tooltip\";\nimport { TooltipPlacement } from \"./useTooltipAnchoredPosition\";\n\nexport interface TooltipHookProps {\n anchorQuery?: string;\n id: string;\n placement?: TooltipPlacement | TooltipPlacement[];\n tooltipContent: ReactNode;\n}\n\nexport const useTooltip = ({\n anchorQuery = \"*\",\n id: idProp,\n placement = [\"right\", \"above\", \"below\"],\n tooltipContent,\n}: TooltipHookProps) => {\n const hideTooltipRef = useRef<() => void>(undefined);\n const isHoveringRef = useRef(false);\n const anchorElementRef = useRef<HTMLElement | null>(null);\n const mouseEnterTimerRef = useRef<number | undefined>(undefined);\n const mouseLeaveTimerRef = useRef<number | undefined>(undefined);\n const [tooltipProps, setTooltipProps] = useState<TooltipProps | undefined>();\n\n const id = useId(idProp);\n\n const escapeListener = useCallback((evt: KeyboardEvent) => {\n if (evt.key === \"Escape\") {\n hideTooltipRef.current?.();\n }\n }, []);\n\n hideTooltipRef.current = useCallback(() => {\n setTooltipProps(undefined);\n document.removeEventListener(\"keydown\", escapeListener);\n }, [escapeListener]);\n\n const handleMouseEnterTooltip = useCallback(() => {\n window.clearTimeout(mouseLeaveTimerRef.current);\n }, []);\n\n const handleMouseLeaveTooltip = useCallback(() => {\n hideTooltipRef.current?.();\n }, []);\n\n const hideTooltip = useCallback((defer = 0) => {\n if (mouseEnterTimerRef.current) {\n window.clearTimeout(mouseEnterTimerRef.current);\n mouseEnterTimerRef.current = undefined;\n } else if (hideTooltipRef.current) {\n if (defer === 0) {\n hideTooltipRef.current();\n } else {\n mouseLeaveTimerRef.current = window.setTimeout(\n hideTooltipRef.current,\n defer,\n );\n }\n }\n }, []);\n\n const showTooltip = useCallback(\n (ref = anchorElementRef) => {\n const { current: anchorEl } = ref;\n if (anchorEl) {\n setTooltipProps({\n anchorElement: ref,\n children: tooltipContent,\n id: `${id}-tooltip`,\n onMouseEnter: handleMouseEnterTooltip,\n onMouseLeave: handleMouseLeaveTooltip,\n placement: placement,\n });\n // register ESC listener\n document.addEventListener(\"keydown\", escapeListener);\n }\n mouseEnterTimerRef.current = undefined;\n hideTooltip(isHoveringRef.current ? 3000 : 1000);\n },\n [\n escapeListener,\n handleMouseEnterTooltip,\n handleMouseLeaveTooltip,\n hideTooltip,\n id,\n placement,\n tooltipContent,\n ],\n );\n\n const handleMouseEnter = useCallback(\n (evt: MouseEvent) => {\n isHoveringRef.current = true;\n const el = queryClosest(evt.target, anchorQuery);\n if (el) {\n console.log(`el ${el.classList}`);\n anchorElementRef.current = el;\n mouseEnterTimerRef.current = window.setTimeout(showTooltip, 800);\n }\n },\n [anchorQuery, showTooltip],\n );\n\n const handleMouseLeave = useCallback(() => {\n isHoveringRef.current = false;\n hideTooltip(200);\n }, [hideTooltip]);\n\n const anchorProps = {\n \"aria-describedby\": `${id}-tooltip`,\n onMouseEnter: handleMouseEnter,\n onMouseLeave: handleMouseLeave,\n };\n\n return {\n anchorProps,\n hideTooltip,\n showTooltip,\n tooltipProps,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
|
|
3
|
-
const pointerSize = 12;
|
|
4
|
-
const roomAbove = (anchor, tooltip) => tooltip.height + pointerSize < anchor.top;
|
|
5
|
-
const roomLeft = (anchor, tooltip) => tooltip.width + pointerSize < anchor.left;
|
|
6
|
-
const roomRight = (anchor, tooltip) => anchor.right + tooltip.width + pointerSize < document.body.clientWidth;
|
|
7
|
-
const roomBelow = (anchor, tooltip) => document.body.clientHeight - anchor.bottom > tooltip.height + pointerSize;
|
|
8
|
-
const roomAvailableAtPlacement = (placement, anchor, tooltip) => {
|
|
9
|
-
switch (placement) {
|
|
10
|
-
case "above":
|
|
11
|
-
return roomAbove(anchor, tooltip);
|
|
12
|
-
case "left":
|
|
13
|
-
return roomLeft(anchor, tooltip);
|
|
14
|
-
case "below":
|
|
15
|
-
return roomBelow(anchor, tooltip);
|
|
16
|
-
case "right":
|
|
17
|
-
return roomRight(anchor, tooltip);
|
|
18
|
-
default:
|
|
19
|
-
throw Error("invalid tooltip placement");
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
const positionAbove = (anchor, tooltip) => ({
|
|
23
|
-
left: anchor.left - (tooltip.width - anchor.width) / 2,
|
|
24
|
-
top: anchor.top - (tooltip.height + pointerSize)
|
|
25
|
-
});
|
|
26
|
-
const positionBelow = (anchor, tooltip) => ({
|
|
27
|
-
left: anchor.left - (tooltip.width - anchor.width) / 2,
|
|
28
|
-
top: anchor.bottom + pointerSize
|
|
29
|
-
});
|
|
30
|
-
const positionLeft = (anchor, tooltip) => ({
|
|
31
|
-
left: anchor.left - pointerSize - tooltip.width,
|
|
32
|
-
top: anchor.top - (tooltip.height - anchor.height) / 2
|
|
33
|
-
});
|
|
34
|
-
const positionRight = (anchor, tooltip) => ({
|
|
35
|
-
left: anchor.right + pointerSize,
|
|
36
|
-
top: anchor.top - (tooltip.height - anchor.height) / 2
|
|
37
|
-
});
|
|
38
|
-
const positionAtPlacement = (placement, anchor, tooltip) => {
|
|
39
|
-
switch (placement) {
|
|
40
|
-
case "above":
|
|
41
|
-
return positionAbove(anchor, tooltip);
|
|
42
|
-
case "left":
|
|
43
|
-
return positionLeft(anchor, tooltip);
|
|
44
|
-
case "below":
|
|
45
|
-
return positionBelow(anchor, tooltip);
|
|
46
|
-
case "right":
|
|
47
|
-
return positionRight(anchor, tooltip);
|
|
48
|
-
default:
|
|
49
|
-
throw Error("invalid tooltip placement");
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
const keepWithinTheScreen = ({ height, width }, position) => {
|
|
53
|
-
const { clientWidth, clientHeight } = document.body;
|
|
54
|
-
let { left, top } = position;
|
|
55
|
-
if (left + width > clientWidth) {
|
|
56
|
-
left -= left + width - clientWidth;
|
|
57
|
-
}
|
|
58
|
-
if (left < 0) {
|
|
59
|
-
left = 0;
|
|
60
|
-
}
|
|
61
|
-
if (top + height > clientHeight) {
|
|
62
|
-
top -= top + height - clientHeight;
|
|
63
|
-
}
|
|
64
|
-
if (top < 0) {
|
|
65
|
-
top = 0;
|
|
66
|
-
}
|
|
67
|
-
return { left, top };
|
|
68
|
-
};
|
|
69
|
-
const toCSSText = ({ left, top }) => `left:${left}px;top:${top}px;opacity:1;`;
|
|
70
|
-
const getNextPlacement = (placement) => {
|
|
71
|
-
if (Array.isArray(placement)) {
|
|
72
|
-
if (placement.length === 0) {
|
|
73
|
-
return [void 0, placement];
|
|
74
|
-
} else {
|
|
75
|
-
return [placement[0], placement.slice(1)];
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
return [placement, []];
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
const useTooltipAnchoredPosition = ({
|
|
82
|
-
anchorElement,
|
|
83
|
-
placement
|
|
84
|
-
}) => {
|
|
85
|
-
const ref = useCallback(
|
|
86
|
-
(el) => {
|
|
87
|
-
if (el && anchorElement.current) {
|
|
88
|
-
const anchorRect = anchorElement.current.getBoundingClientRect();
|
|
89
|
-
const tooltipRect = el.getBoundingClientRect();
|
|
90
|
-
let nextPlacement;
|
|
91
|
-
let placements = placement;
|
|
92
|
-
[nextPlacement = "right", placements] = getNextPlacement(placements);
|
|
93
|
-
do {
|
|
94
|
-
if (roomAvailableAtPlacement(nextPlacement, anchorRect, tooltipRect)) {
|
|
95
|
-
el.style.cssText = toCSSText(
|
|
96
|
-
keepWithinTheScreen(
|
|
97
|
-
tooltipRect,
|
|
98
|
-
positionAtPlacement(nextPlacement, anchorRect, tooltipRect)
|
|
99
|
-
)
|
|
100
|
-
);
|
|
101
|
-
el.dataset.align = nextPlacement;
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
[nextPlacement, placements] = getNextPlacement(placements);
|
|
105
|
-
} while (nextPlacement);
|
|
106
|
-
}
|
|
107
|
-
el?.classList.remove("vuuHidden");
|
|
108
|
-
},
|
|
109
|
-
[anchorElement, placement]
|
|
110
|
-
);
|
|
111
|
-
return ref;
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export { useTooltipAnchoredPosition };
|
|
115
|
-
//# sourceMappingURL=useTooltipAnchoredPosition.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTooltipAnchoredPosition.js","sources":["../../../../packages/vuu-popups/src/tooltip/useTooltipAnchoredPosition.ts"],"sourcesContent":["// TODO merge with Popup\n\nimport { RefCallback, RefObject, useCallback } from \"react\";\n\nexport type TooltipPlacement = \"above\" | \"right\" | \"below\" | \"left\";\n\nconst pointerSize = 12;\nexport interface TooltipAnchoredPositionHookProps {\n anchorElement: RefObject<HTMLElement | null>;\n placement: TooltipPlacement | TooltipPlacement[];\n}\n\nconst roomAbove = (anchor: DOMRect, tooltip: DOMRect) =>\n tooltip.height + pointerSize < anchor.top;\nconst roomLeft = (anchor: DOMRect, tooltip: DOMRect) =>\n tooltip.width + pointerSize < anchor.left;\nconst roomRight = (anchor: DOMRect, tooltip: DOMRect) =>\n anchor.right + tooltip.width + pointerSize < document.body.clientWidth;\nconst roomBelow = (anchor: DOMRect, tooltip: DOMRect) =>\n document.body.clientHeight - anchor.bottom > tooltip.height + pointerSize;\n\nconst roomAvailableAtPlacement = (\n placement: TooltipPlacement,\n anchor: DOMRect,\n tooltip: DOMRect,\n) => {\n switch (placement) {\n case \"above\":\n return roomAbove(anchor, tooltip);\n case \"left\":\n return roomLeft(anchor, tooltip);\n case \"below\":\n return roomBelow(anchor, tooltip);\n case \"right\":\n return roomRight(anchor, tooltip);\n default:\n throw Error(\"invalid tooltip placement\");\n }\n};\n\ntype Position = { left: number; top: number };\ntype Positioner = (anchorRect: DOMRect, tooltipRect: DOMRect) => Position;\n\nconst positionAbove: Positioner = (anchor, tooltip) => ({\n left: anchor.left - (tooltip.width - anchor.width) / 2,\n top: anchor.top - (tooltip.height + pointerSize),\n});\n\nconst positionBelow: Positioner = (anchor, tooltip) => ({\n left: anchor.left - (tooltip.width - anchor.width) / 2,\n top: anchor.bottom + pointerSize,\n});\nconst positionLeft: Positioner = (anchor, tooltip) => ({\n left: anchor.left - pointerSize - tooltip.width,\n top: anchor.top - (tooltip.height - anchor.height) / 2,\n});\n\nconst positionRight: Positioner = (anchor, tooltip) => ({\n left: anchor.right + pointerSize,\n top: anchor.top - (tooltip.height - anchor.height) / 2,\n});\n\nconst positionAtPlacement = (\n placement: TooltipPlacement,\n anchor: DOMRect,\n tooltip: DOMRect,\n) => {\n switch (placement) {\n case \"above\":\n return positionAbove(anchor, tooltip);\n case \"left\":\n return positionLeft(anchor, tooltip);\n case \"below\":\n return positionBelow(anchor, tooltip);\n case \"right\":\n return positionRight(anchor, tooltip);\n default:\n throw Error(\"invalid tooltip placement\");\n }\n};\n\nconst keepWithinTheScreen = (\n { height, width }: DOMRect,\n position: Position,\n) => {\n const { clientWidth, clientHeight } = document.body;\n let { left, top } = position;\n if (left + width > clientWidth) {\n left -= left + width - clientWidth;\n }\n if (left < 0) {\n left = 0;\n }\n if (top + height > clientHeight) {\n top -= top + height - clientHeight;\n }\n if (top < 0) {\n top = 0;\n }\n\n return { left, top };\n};\n\nconst toCSSText = ({ left, top }: Position) =>\n `left:${left}px;top:${top}px;opacity:1;`;\n\nconst getNextPlacement = (\n placement: TooltipPlacement | TooltipPlacement[],\n): [TooltipPlacement | undefined, TooltipPlacement[]] => {\n if (Array.isArray(placement)) {\n if (placement.length === 0) {\n return [undefined, placement];\n } else {\n return [placement[0], placement.slice(1)];\n }\n } else {\n return [placement, []];\n }\n};\n\nexport const useTooltipAnchoredPosition = ({\n anchorElement,\n placement,\n}: TooltipAnchoredPositionHookProps) => {\n const ref = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n if (el && anchorElement.current) {\n const anchorRect = anchorElement.current.getBoundingClientRect();\n const tooltipRect = el.getBoundingClientRect();\n let nextPlacement: TooltipPlacement | undefined;\n let placements: TooltipPlacement | TooltipPlacement[] = placement;\n [nextPlacement = \"right\", placements] = getNextPlacement(placements);\n do {\n if (\n roomAvailableAtPlacement(nextPlacement, anchorRect, tooltipRect)\n ) {\n el.style.cssText = toCSSText(\n keepWithinTheScreen(\n tooltipRect,\n positionAtPlacement(nextPlacement, anchorRect, tooltipRect),\n ),\n );\n el.dataset.align = nextPlacement;\n return;\n }\n [nextPlacement, placements] = getNextPlacement(placements);\n } while (nextPlacement);\n }\n el?.classList.remove(\"vuuHidden\");\n },\n [anchorElement, placement],\n );\n return ref;\n};\n"],"names":[],"mappings":";;AAMA,MAAM,WAAc,GAAA,EAAA;AAMpB,MAAM,YAAY,CAAC,MAAA,EAAiB,YAClC,OAAQ,CAAA,MAAA,GAAS,cAAc,MAAO,CAAA,GAAA;AACxC,MAAM,WAAW,CAAC,MAAA,EAAiB,YACjC,OAAQ,CAAA,KAAA,GAAQ,cAAc,MAAO,CAAA,IAAA;AACvC,MAAM,SAAA,GAAY,CAAC,MAAA,EAAiB,OAClC,KAAA,MAAA,CAAO,QAAQ,OAAQ,CAAA,KAAA,GAAQ,WAAc,GAAA,QAAA,CAAS,IAAK,CAAA,WAAA;AAC7D,MAAM,SAAA,GAAY,CAAC,MAAA,EAAiB,OAClC,KAAA,QAAA,CAAS,KAAK,YAAe,GAAA,MAAA,CAAO,MAAS,GAAA,OAAA,CAAQ,MAAS,GAAA,WAAA;AAEhE,MAAM,wBAA2B,GAAA,CAC/B,SACA,EAAA,MAAA,EACA,OACG,KAAA;AACH,EAAA,QAAQ,SAAW;AAAA,IACjB,KAAK,OAAA;AACH,MAAO,OAAA,SAAA,CAAU,QAAQ,OAAO,CAAA;AAAA,IAClC,KAAK,MAAA;AACH,MAAO,OAAA,QAAA,CAAS,QAAQ,OAAO,CAAA;AAAA,IACjC,KAAK,OAAA;AACH,MAAO,OAAA,SAAA,CAAU,QAAQ,OAAO,CAAA;AAAA,IAClC,KAAK,OAAA;AACH,MAAO,OAAA,SAAA,CAAU,QAAQ,OAAO,CAAA;AAAA,IAClC;AACE,MAAA,MAAM,MAAM,2BAA2B,CAAA;AAAA;AAE7C,CAAA;AAKA,MAAM,aAAA,GAA4B,CAAC,MAAA,EAAQ,OAAa,MAAA;AAAA,EACtD,MAAM,MAAO,CAAA,IAAA,GAAA,CAAQ,OAAQ,CAAA,KAAA,GAAQ,OAAO,KAAS,IAAA,CAAA;AAAA,EACrD,GAAK,EAAA,MAAA,CAAO,GAAO,IAAA,OAAA,CAAQ,MAAS,GAAA,WAAA;AACtC,CAAA,CAAA;AAEA,MAAM,aAAA,GAA4B,CAAC,MAAA,EAAQ,OAAa,MAAA;AAAA,EACtD,MAAM,MAAO,CAAA,IAAA,GAAA,CAAQ,OAAQ,CAAA,KAAA,GAAQ,OAAO,KAAS,IAAA,CAAA;AAAA,EACrD,GAAA,EAAK,OAAO,MAAS,GAAA;AACvB,CAAA,CAAA;AACA,MAAM,YAAA,GAA2B,CAAC,MAAA,EAAQ,OAAa,MAAA;AAAA,EACrD,IAAM,EAAA,MAAA,CAAO,IAAO,GAAA,WAAA,GAAc,OAAQ,CAAA,KAAA;AAAA,EAC1C,KAAK,MAAO,CAAA,GAAA,GAAA,CAAO,OAAQ,CAAA,MAAA,GAAS,OAAO,MAAU,IAAA;AACvD,CAAA,CAAA;AAEA,MAAM,aAAA,GAA4B,CAAC,MAAA,EAAQ,OAAa,MAAA;AAAA,EACtD,IAAA,EAAM,OAAO,KAAQ,GAAA,WAAA;AAAA,EACrB,KAAK,MAAO,CAAA,GAAA,GAAA,CAAO,OAAQ,CAAA,MAAA,GAAS,OAAO,MAAU,IAAA;AACvD,CAAA,CAAA;AAEA,MAAM,mBAAsB,GAAA,CAC1B,SACA,EAAA,MAAA,EACA,OACG,KAAA;AACH,EAAA,QAAQ,SAAW;AAAA,IACjB,KAAK,OAAA;AACH,MAAO,OAAA,aAAA,CAAc,QAAQ,OAAO,CAAA;AAAA,IACtC,KAAK,MAAA;AACH,MAAO,OAAA,YAAA,CAAa,QAAQ,OAAO,CAAA;AAAA,IACrC,KAAK,OAAA;AACH,MAAO,OAAA,aAAA,CAAc,QAAQ,OAAO,CAAA;AAAA,IACtC,KAAK,OAAA;AACH,MAAO,OAAA,aAAA,CAAc,QAAQ,OAAO,CAAA;AAAA,IACtC;AACE,MAAA,MAAM,MAAM,2BAA2B,CAAA;AAAA;AAE7C,CAAA;AAEA,MAAM,sBAAsB,CAC1B,EAAE,MAAQ,EAAA,KAAA,IACV,QACG,KAAA;AACH,EAAA,MAAM,EAAE,WAAA,EAAa,YAAa,EAAA,GAAI,QAAS,CAAA,IAAA;AAC/C,EAAI,IAAA,EAAE,IAAM,EAAA,GAAA,EAAQ,GAAA,QAAA;AACpB,EAAI,IAAA,IAAA,GAAO,QAAQ,WAAa,EAAA;AAC9B,IAAA,IAAA,IAAQ,OAAO,KAAQ,GAAA,WAAA;AAAA;AAEzB,EAAA,IAAI,OAAO,CAAG,EAAA;AACZ,IAAO,IAAA,GAAA,CAAA;AAAA;AAET,EAAI,IAAA,GAAA,GAAM,SAAS,YAAc,EAAA;AAC/B,IAAA,GAAA,IAAO,MAAM,MAAS,GAAA,YAAA;AAAA;AAExB,EAAA,IAAI,MAAM,CAAG,EAAA;AACX,IAAM,GAAA,GAAA,CAAA;AAAA;AAGR,EAAO,OAAA,EAAE,MAAM,GAAI,EAAA;AACrB,CAAA;AAEA,MAAM,SAAA,GAAY,CAAC,EAAE,IAAA,EAAM,KACzB,KAAA,CAAA,KAAA,EAAQ,IAAI,CAAA,OAAA,EAAU,GAAG,CAAA,aAAA,CAAA;AAE3B,MAAM,gBAAA,GAAmB,CACvB,SACuD,KAAA;AACvD,EAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,SAAS,CAAG,EAAA;AAC5B,IAAI,IAAA,SAAA,CAAU,WAAW,CAAG,EAAA;AAC1B,MAAO,OAAA,CAAC,QAAW,SAAS,CAAA;AAAA,KACvB,MAAA;AACL,MAAA,OAAO,CAAC,SAAU,CAAA,CAAC,GAAG,SAAU,CAAA,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA;AAC1C,GACK,MAAA;AACL,IAAO,OAAA,CAAC,SAAW,EAAA,EAAE,CAAA;AAAA;AAEzB,CAAA;AAEO,MAAM,6BAA6B,CAAC;AAAA,EACzC,aAAA;AAAA,EACA;AACF,CAAwC,KAAA;AACtC,EAAA,MAAM,GAAM,GAAA,WAAA;AAAA,IACV,CAAC,EAAO,KAAA;AACN,MAAI,IAAA,EAAA,IAAM,cAAc,OAAS,EAAA;AAC/B,QAAM,MAAA,UAAA,GAAa,aAAc,CAAA,OAAA,CAAQ,qBAAsB,EAAA;AAC/D,QAAM,MAAA,WAAA,GAAc,GAAG,qBAAsB,EAAA;AAC7C,QAAI,IAAA,aAAA;AACJ,QAAA,IAAI,UAAoD,GAAA,SAAA;AACxD,QAAA,CAAC,aAAgB,GAAA,OAAA,EAAS,UAAU,CAAA,GAAI,iBAAiB,UAAU,CAAA;AACnE,QAAG,GAAA;AACD,UAAA,IACE,wBAAyB,CAAA,aAAA,EAAe,UAAY,EAAA,WAAW,CAC/D,EAAA;AACA,YAAA,EAAA,CAAG,MAAM,OAAU,GAAA,SAAA;AAAA,cACjB,mBAAA;AAAA,gBACE,WAAA;AAAA,gBACA,mBAAA,CAAoB,aAAe,EAAA,UAAA,EAAY,WAAW;AAAA;AAC5D,aACF;AACA,YAAA,EAAA,CAAG,QAAQ,KAAQ,GAAA,aAAA;AACnB,YAAA;AAAA;AAEF,UAAA,CAAC,aAAe,EAAA,UAAU,CAAI,GAAA,gBAAA,CAAiB,UAAU,CAAA;AAAA,SAClD,QAAA,aAAA;AAAA;AAEX,MAAI,EAAA,EAAA,SAAA,CAAU,OAAO,WAAW,CAAA;AAAA,KAClC;AAAA,IACA,CAAC,eAAe,SAAS;AAAA,GAC3B;AACA,EAAO,OAAA,GAAA;AACT;;;;"}
|