@amboss/design-system 3.21.1 → 3.21.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.
Files changed (19) hide show
  1. package/build/cjs/components/UserHighlightTooltip/-types.d.ts +5 -0
  2. package/build/cjs/components/UserHighlightTooltip/-types.js +1 -0
  3. package/build/cjs/components/UserHighlightTooltip/-utils.ts/TooltipRegistry.d.ts +35 -0
  4. package/build/cjs/components/UserHighlightTooltip/-utils.ts/TooltipRegistry.js +1 -0
  5. package/build/cjs/components/UserHighlightTooltip/-utils.ts/findOverlappingTooltips.d.ts +15 -0
  6. package/build/cjs/components/UserHighlightTooltip/-utils.ts/findOverlappingTooltips.js +1 -0
  7. package/build/cjs/components/UserHighlightTooltip/-utils.ts/getTopmostElement.d.ts +8 -0
  8. package/build/cjs/components/UserHighlightTooltip/-utils.ts/getTopmostElement.js +1 -0
  9. package/build/cjs/components/UserHighlightTooltip/UserHighlightTooltip.js +1 -1
  10. package/build/esm/components/UserHighlightTooltip/-types.d.ts +5 -0
  11. package/build/esm/components/UserHighlightTooltip/-types.js +1 -0
  12. package/build/esm/components/UserHighlightTooltip/-utils.ts/TooltipRegistry.d.ts +35 -0
  13. package/build/esm/components/UserHighlightTooltip/-utils.ts/TooltipRegistry.js +1 -0
  14. package/build/esm/components/UserHighlightTooltip/-utils.ts/findOverlappingTooltips.d.ts +15 -0
  15. package/build/esm/components/UserHighlightTooltip/-utils.ts/findOverlappingTooltips.js +1 -0
  16. package/build/esm/components/UserHighlightTooltip/-utils.ts/getTopmostElement.d.ts +8 -0
  17. package/build/esm/components/UserHighlightTooltip/-utils.ts/getTopmostElement.js +1 -0
  18. package/build/esm/components/UserHighlightTooltip/UserHighlightTooltip.js +1 -1
  19. package/package.json +1 -1
@@ -0,0 +1,5 @@
1
+ export type TooltipInstance = {
2
+ id: string;
3
+ triggerElements: HTMLElement[];
4
+ setVisible: (visible: boolean) => void;
5
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});
@@ -0,0 +1,35 @@
1
+ import type { TooltipInstance } from "../-types";
2
+ /**
3
+ * Module-scoped registry manager for tooltip instances.
4
+ * Uses a Map internally but provides cleanup and HMR resilience.
5
+ * This is module-scoped (not component-scoped) because tooltips need to
6
+ * coordinate across all instances globally to handle overlapping scenarios.
7
+ */
8
+ export declare class TooltipRegistry {
9
+ private registry;
10
+ private isCleaningUp;
11
+ /**
12
+ * Register a tooltip instance
13
+ */
14
+ set(id: string, instance: TooltipInstance): void;
15
+ /**
16
+ * Unregister a tooltip instance
17
+ */
18
+ delete(id: string): void;
19
+ /**
20
+ * Get all registered instances (for iteration)
21
+ */
22
+ values(): IterableIterator<TooltipInstance>;
23
+ /**
24
+ * Get the registry size
25
+ */
26
+ get size(): number;
27
+ /**
28
+ * Clear all entries (useful for HMR or testing)
29
+ */
30
+ clear(): void;
31
+ /**
32
+ * Clean up potentially stale entries by checking if trigger elements are still in DOM
33
+ */
34
+ private cleanupStaleEntries;
35
+ }
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"TooltipRegistry",{enumerable:!0,get:function(){return TooltipRegistry}});class TooltipRegistry{set(id,instance){this.registry.size>100&&!this.isCleaningUp&&this.cleanupStaleEntries(),this.registry.set(id,instance)}delete(id){this.registry.delete(id)}values(){return this.registry.values()}get size(){return this.registry.size}clear(){this.registry.clear()}cleanupStaleEntries(){this.isCleaningUp=!0;try{Array.from(this.registry.entries()).filter(([,instance])=>instance.triggerElements.every(element=>!document.contains(element))).map(([id])=>id).forEach(id=>this.registry.delete(id))}finally{this.isCleaningUp=!1}}constructor(){this.registry=new Map,this.isCleaningUp=!1}}
@@ -0,0 +1,15 @@
1
+ import type { TooltipInstance } from "../-types";
2
+ /**
3
+ * Registry interface for tooltip coordination.
4
+ * Allows the utility function to work with different registry implementations.
5
+ */
6
+ export interface TooltipRegistryInterface {
7
+ values(): IterableIterator<TooltipInstance>;
8
+ }
9
+ /**
10
+ * Finds all tooltip instances that have trigger elements containing the currently hovered element.
11
+ * A tooltip is considered overlapping when:
12
+ * - The hovered element is one of the trigger elements, OR
13
+ * - The hovered element is contained by one of the trigger elements
14
+ */
15
+ export declare function findOverlappingTooltips(hoveredElement: HTMLElement, excludeId: string, tooltipRegistry: TooltipRegistryInterface): TooltipInstance[];
@@ -0,0 +1 @@
1
+ "use strict";function findOverlappingTooltips(hoveredElement,excludeId,tooltipRegistry){return Array.from(tooltipRegistry.values()).filter(instance=>instance.id!==excludeId).filter(instance=>instance.triggerElements.some(triggerElement=>!!(triggerElement===hoveredElement||triggerElement.contains(hoveredElement))))}Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"findOverlappingTooltips",{enumerable:!0,get:function(){return findOverlappingTooltips}});
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Determines which element is on top when multiple elements overlap.
3
+ * Priority:
4
+ * 1. If pointer coordinates are available, use elementsFromPoint (most accurate)
5
+ * 2. If elements are nested, the most-nested (contained) element is on top
6
+ * 3. Otherwise, elements that appear later in DOM order are on top
7
+ */
8
+ export declare function getTopmostElement(elements: HTMLElement[], pointerEvent?: Event): HTMLElement | null;
@@ -0,0 +1 @@
1
+ "use strict";function getTopmostElement(elements,pointerEvent){if(0===elements.length)return null;if(1===elements.length)return elements[0];if(pointerEvent&&"clientX"in pointerEvent&&"clientY"in pointerEvent)try{let foundElement=document.elementsFromPoint(pointerEvent.clientX,pointerEvent.clientY).find(elementAtPoint=>!!elements.includes(elementAtPoint)||elements.some(element=>element.contains(elementAtPoint)));if(foundElement){if(elements.includes(foundElement))return foundElement;let containingElements=elements.filter(element=>element.contains(foundElement));if(containingElements.length>0)return containingElements.sort((a,b)=>a.contains(b)?-1:+!!b.contains(a)),containingElements[containingElements.length-1]}}catch{}let topmost=elements?.[0];return elements?.slice(1)?.forEach(element=>{topmost.contains(element)&&!element.contains(topmost)?topmost=element:element.contains(topmost)&&!topmost.contains(element)||(topmost.compareDocumentPosition(element)&Node.DOCUMENT_POSITION_FOLLOWING)!=0&&(topmost=element)}),topmost}Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"getTopmostElement",{enumerable:!0,get:function(){return getTopmostElement}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"UserHighlightTooltip",{enumerable:!0,get:function(){return UserHighlightTooltip}});const _react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_TooltipContent=require("../Tooltip/TooltipContent");function UserHighlightTooltip({content,contentPadding="s",placement="auto",maxWidth,portalContainer,"data-e2e-test-id":dataE2eTestId,triggerElements,selectedRange,onVisibilityChange,positionAtStart}){let tooltipId=(0,_react.useMemo)(()=>`DSUserHighlightTooltip_${Math.floor(Date.now()*Math.random())}`,[]),isTooltipHovered=(0,_react.useRef)(!1),showTooltipTimeoutId=(0,_react.useRef)(null),hideTooltipTimeoutId=(0,_react.useRef)(null),triggerHovered=(0,_react.useRef)(!1),rangeRef=(0,_react.useRef)(null);(0,_react.useEffect)(()=>{if(selectedRange)rangeRef.current=selectedRange;else{let range=document.createRange();if(positionAtStart){let text=triggerElements[0].childNodes[0];range.setStart(text,0),range.setEnd(text,1)}else range.setStart(triggerElements[0],0),range.setEnd(triggerElements[triggerElements.length-1],1);rangeRef.current=range}},[triggerElements,selectedRange,positionAtStart]);let[tooltipVisible,setTooltipVisible]=(0,_react.useState)(!1),toggleVisibility=(0,_react.useCallback)(status=>{setTooltipVisible(status),onVisibilityChange&&onVisibilityChange(status)},[onVisibilityChange]);(0,_react.useEffect)(()=>{selectedRange&&toggleVisibility(!0)},[]);let hideTooltipAfterDelay=(0,_react.useCallback)(()=>{hideTooltipTimeoutId.current=setTimeout(()=>{triggerHovered.current||isTooltipHovered.current||!tooltipVisible||toggleVisibility(!1)},200)},[toggleVisibility,tooltipVisible]),handleTriggerPointerEnter=(0,_react.useCallback)(()=>{triggerHovered.current=!0,tooltipVisible||(clearTimeout(showTooltipTimeoutId.current),showTooltipTimeoutId.current=setTimeout(()=>{!tooltipVisible&&triggerHovered.current&&toggleVisibility(!0)},200))},[toggleVisibility,tooltipVisible]),handleTriggerPointerLeave=(0,_react.useCallback)(()=>{clearTimeout(hideTooltipTimeoutId.current),triggerHovered.current=!1,hideTooltipAfterDelay()},[hideTooltipAfterDelay]);return((0,_react.useEffect)(()=>()=>{clearTimeout(showTooltipTimeoutId.current),clearTimeout(hideTooltipTimeoutId.current)},[]),(0,_react.useEffect)(()=>(triggerElements.forEach(node=>{node.addEventListener("pointerenter",handleTriggerPointerEnter),node.addEventListener("pointerleave",handleTriggerPointerLeave)}),()=>{triggerElements.forEach(node=>{node.removeEventListener("pointerenter",handleTriggerPointerEnter),node.removeEventListener("pointerleave",handleTriggerPointerLeave)})}),[handleTriggerPointerEnter,handleTriggerPointerLeave,triggerElements]),(0,_react.useEffect)(()=>{triggerElements.forEach(node=>{tooltipVisible?node.setAttribute("aria-describedby",tooltipId):node.removeAttribute("aria-describedby")})},[tooltipId,tooltipVisible,triggerElements]),rangeRef.current)?_react.default.createElement(_TooltipContent.TooltipContent,{dataDSId:"UserHighlightTooltip",content:content,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,isVisible:tooltipVisible,tooltipId:tooltipId,triggerRef:rangeRef,role:"tooltip",contentPadding:contentPadding,maxWidth:maxWidth,subTheme:"inverted",onTooltipPointerEnter:()=>{isTooltipHovered.current=!0},onTooltipPointerLeave:()=>{clearTimeout(hideTooltipTimeoutId.current),isTooltipHovered.current=!1,hideTooltipAfterDelay()}}):null}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"UserHighlightTooltip",{enumerable:!0,get:function(){return UserHighlightTooltip}});const _react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_TooltipContent=require("../Tooltip/TooltipContent"),_findOverlappingTooltips=require("./-utils.ts/findOverlappingTooltips"),_getTopmostElement=require("./-utils.ts/getTopmostElement"),tooltipRegistry=new(require("./-utils.ts/TooltipRegistry")).TooltipRegistry;function UserHighlightTooltip({content,contentPadding="s",placement="auto",maxWidth,portalContainer,"data-e2e-test-id":dataE2eTestId,triggerElements,selectedRange,onVisibilityChange,positionAtStart}){let tooltipId=(0,_react.useMemo)(()=>`DSUserHighlightTooltip_${Math.floor(Date.now()*Math.random())}`,[]),instanceId=(0,_react.useId)(),isTooltipHovered=(0,_react.useRef)(!1),showTooltipTimeoutId=(0,_react.useRef)(null),hideTooltipTimeoutId=(0,_react.useRef)(null),triggerHovered=(0,_react.useRef)(!1),rangeRef=(0,_react.useRef)(null);(0,_react.useEffect)(()=>{if(selectedRange)rangeRef.current=selectedRange;else{let range=document.createRange();if(positionAtStart){let text=triggerElements[0].childNodes[0];range.setStart(text,0),range.setEnd(text,1)}else range.setStart(triggerElements[0],0),range.setEnd(triggerElements[triggerElements.length-1],1);rangeRef.current=range}},[triggerElements,selectedRange,positionAtStart]);let[tooltipVisible,setTooltipVisible]=(0,_react.useState)(!1),toggleVisibility=(0,_react.useCallback)(status=>{setTooltipVisible(status),onVisibilityChange&&onVisibilityChange(status)},[onVisibilityChange]);(0,_react.useEffect)(()=>(tooltipRegistry.set(instanceId,{id:instanceId,triggerElements,setVisible:visible=>{setTooltipVisible(visible),onVisibilityChange&&onVisibilityChange(visible)}}),()=>{tooltipRegistry.delete(instanceId)}),[instanceId,triggerElements,onVisibilityChange]),(0,_react.useEffect)(()=>{selectedRange&&toggleVisibility(!0)},[]);let hideTooltipAfterDelay=(0,_react.useCallback)(()=>{hideTooltipTimeoutId.current=setTimeout(()=>{triggerHovered.current||isTooltipHovered.current||!tooltipVisible||toggleVisibility(!1)},200)},[toggleVisibility,tooltipVisible]),handleTriggerPointerEnter=(0,_react.useCallback)(event=>{triggerHovered.current=!0,clearTimeout(showTooltipTimeoutId.current),showTooltipTimeoutId.current=setTimeout(()=>{if(triggerHovered.current){let hoveredElement=event?.target||triggerElements[0],overlappingTooltips=(0,_findOverlappingTooltips.findOverlappingTooltips)(hoveredElement,instanceId,tooltipRegistry);if(overlappingTooltips.length>0){let allOverlappingElements=[...triggerElements];overlappingTooltips.forEach(tooltip=>{allOverlappingElements.push(...tooltip.triggerElements)});let topmostElement=(0,_getTopmostElement.getTopmostElement)(allOverlappingElements,event);!topmostElement||triggerElements.includes(topmostElement)?(overlappingTooltips.forEach(tooltip=>{tooltip.setVisible(!1)}),tooltipVisible||toggleVisibility(!0)):tooltipVisible&&toggleVisibility(!1)}else tooltipVisible||toggleVisibility(!0)}},200)},[toggleVisibility,tooltipVisible,triggerElements,instanceId]),handleTriggerPointerLeave=(0,_react.useCallback)(event=>{if(clearTimeout(hideTooltipTimeoutId.current),triggerHovered.current=!1,event&&"clientX"in event&&"clientY"in event)try{let elementUnderPointer=document.elementFromPoint(event.clientX,event.clientY);if(elementUnderPointer){let overlappingTooltips=(0,_findOverlappingTooltips.findOverlappingTooltips)(elementUnderPointer,instanceId,tooltipRegistry);if(overlappingTooltips.length>0){let allOverlappingElements=[];overlappingTooltips.forEach(tooltip=>{allOverlappingElements.push(...tooltip.triggerElements)});let topmostElement=(0,_getTopmostElement.getTopmostElement)(allOverlappingElements,event);if(topmostElement&&!triggerElements.includes(topmostElement)){toggleVisibility(!1);let enterEvent=new PointerEvent("pointerenter",{bubbles:!0,cancelable:!0,clientX:event.clientX,clientY:event.clientY,pointerId:event.pointerId,pointerType:event.pointerType});topmostElement.dispatchEvent(enterEvent);return}}}}catch{}hideTooltipAfterDelay()},[hideTooltipAfterDelay,instanceId,toggleVisibility,triggerElements]);return((0,_react.useEffect)(()=>()=>{clearTimeout(showTooltipTimeoutId.current),clearTimeout(hideTooltipTimeoutId.current)},[]),(0,_react.useEffect)(()=>{let wrappedHandleEnter=event=>{handleTriggerPointerEnter(event)};return triggerElements.forEach(node=>{node.addEventListener("pointerenter",wrappedHandleEnter),node.addEventListener("pointerleave",handleTriggerPointerLeave)}),()=>{triggerElements.forEach(node=>{node.removeEventListener("pointerenter",wrappedHandleEnter),node.removeEventListener("pointerleave",handleTriggerPointerLeave)})}},[handleTriggerPointerEnter,handleTriggerPointerLeave,triggerElements]),(0,_react.useEffect)(()=>{triggerElements.forEach(node=>{tooltipVisible?node.setAttribute("aria-describedby",tooltipId):node.removeAttribute("aria-describedby")})},[tooltipId,tooltipVisible,triggerElements]),rangeRef.current)?_react.default.createElement(_TooltipContent.TooltipContent,{dataDSId:"UserHighlightTooltip",content:content,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,isVisible:tooltipVisible,tooltipId:tooltipId,triggerRef:rangeRef,role:"tooltip",contentPadding:contentPadding,maxWidth:maxWidth,subTheme:"inverted",onTooltipPointerEnter:()=>{isTooltipHovered.current=!0},onTooltipPointerLeave:()=>{clearTimeout(hideTooltipTimeoutId.current),isTooltipHovered.current=!1,hideTooltipAfterDelay()}}):null}
@@ -0,0 +1,5 @@
1
+ export type TooltipInstance = {
2
+ id: string;
3
+ triggerElements: HTMLElement[];
4
+ setVisible: (visible: boolean) => void;
5
+ };
@@ -0,0 +1,35 @@
1
+ import type { TooltipInstance } from "../-types";
2
+ /**
3
+ * Module-scoped registry manager for tooltip instances.
4
+ * Uses a Map internally but provides cleanup and HMR resilience.
5
+ * This is module-scoped (not component-scoped) because tooltips need to
6
+ * coordinate across all instances globally to handle overlapping scenarios.
7
+ */
8
+ export declare class TooltipRegistry {
9
+ private registry;
10
+ private isCleaningUp;
11
+ /**
12
+ * Register a tooltip instance
13
+ */
14
+ set(id: string, instance: TooltipInstance): void;
15
+ /**
16
+ * Unregister a tooltip instance
17
+ */
18
+ delete(id: string): void;
19
+ /**
20
+ * Get all registered instances (for iteration)
21
+ */
22
+ values(): IterableIterator<TooltipInstance>;
23
+ /**
24
+ * Get the registry size
25
+ */
26
+ get size(): number;
27
+ /**
28
+ * Clear all entries (useful for HMR or testing)
29
+ */
30
+ clear(): void;
31
+ /**
32
+ * Clean up potentially stale entries by checking if trigger elements are still in DOM
33
+ */
34
+ private cleanupStaleEntries;
35
+ }
@@ -0,0 +1 @@
1
+ export class TooltipRegistry{set(id,instance){this.registry.size>100&&!this.isCleaningUp&&this.cleanupStaleEntries(),this.registry.set(id,instance)}delete(id){this.registry.delete(id)}values(){return this.registry.values()}get size(){return this.registry.size}clear(){this.registry.clear()}cleanupStaleEntries(){this.isCleaningUp=!0;try{Array.from(this.registry.entries()).filter(([,instance])=>instance.triggerElements.every(element=>!document.contains(element))).map(([id])=>id).forEach(id=>this.registry.delete(id))}finally{this.isCleaningUp=!1}}constructor(){this.registry=new Map,this.isCleaningUp=!1}}
@@ -0,0 +1,15 @@
1
+ import type { TooltipInstance } from "../-types";
2
+ /**
3
+ * Registry interface for tooltip coordination.
4
+ * Allows the utility function to work with different registry implementations.
5
+ */
6
+ export interface TooltipRegistryInterface {
7
+ values(): IterableIterator<TooltipInstance>;
8
+ }
9
+ /**
10
+ * Finds all tooltip instances that have trigger elements containing the currently hovered element.
11
+ * A tooltip is considered overlapping when:
12
+ * - The hovered element is one of the trigger elements, OR
13
+ * - The hovered element is contained by one of the trigger elements
14
+ */
15
+ export declare function findOverlappingTooltips(hoveredElement: HTMLElement, excludeId: string, tooltipRegistry: TooltipRegistryInterface): TooltipInstance[];
@@ -0,0 +1 @@
1
+ export function findOverlappingTooltips(hoveredElement,excludeId,tooltipRegistry){return Array.from(tooltipRegistry.values()).filter(instance=>instance.id!==excludeId).filter(instance=>instance.triggerElements.some(triggerElement=>!!(triggerElement===hoveredElement||triggerElement.contains(hoveredElement))))}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Determines which element is on top when multiple elements overlap.
3
+ * Priority:
4
+ * 1. If pointer coordinates are available, use elementsFromPoint (most accurate)
5
+ * 2. If elements are nested, the most-nested (contained) element is on top
6
+ * 3. Otherwise, elements that appear later in DOM order are on top
7
+ */
8
+ export declare function getTopmostElement(elements: HTMLElement[], pointerEvent?: Event): HTMLElement | null;
@@ -0,0 +1 @@
1
+ export function getTopmostElement(elements,pointerEvent){if(0===elements.length)return null;if(1===elements.length)return elements[0];if(pointerEvent&&"clientX"in pointerEvent&&"clientY"in pointerEvent)try{let foundElement=document.elementsFromPoint(pointerEvent.clientX,pointerEvent.clientY).find(elementAtPoint=>!!elements.includes(elementAtPoint)||elements.some(element=>element.contains(elementAtPoint)));if(foundElement){if(elements.includes(foundElement))return foundElement;let containingElements=elements.filter(element=>element.contains(foundElement));if(containingElements.length>0)return containingElements.sort((a,b)=>a.contains(b)?-1:+!!b.contains(a)),containingElements[containingElements.length-1]}}catch{}let topmost=elements?.[0];return elements?.slice(1)?.forEach(element=>{topmost.contains(element)&&!element.contains(topmost)?topmost=element:element.contains(topmost)&&!topmost.contains(element)||(topmost.compareDocumentPosition(element)&Node.DOCUMENT_POSITION_FOLLOWING)!=0&&(topmost=element)}),topmost}
@@ -1 +1 @@
1
- import React,{useCallback,useEffect,useMemo,useRef,useState}from"react";import{TooltipContent}from"../Tooltip/TooltipContent";export function UserHighlightTooltip({content,contentPadding="s",placement="auto",maxWidth,portalContainer,"data-e2e-test-id":dataE2eTestId,triggerElements,selectedRange,onVisibilityChange,positionAtStart}){let tooltipId=useMemo(()=>`DSUserHighlightTooltip_${Math.floor(Date.now()*Math.random())}`,[]),isTooltipHovered=useRef(!1),showTooltipTimeoutId=useRef(null),hideTooltipTimeoutId=useRef(null),triggerHovered=useRef(!1),rangeRef=useRef(null);useEffect(()=>{if(selectedRange)rangeRef.current=selectedRange;else{let range=document.createRange();if(positionAtStart){let text=triggerElements[0].childNodes[0];range.setStart(text,0),range.setEnd(text,1)}else range.setStart(triggerElements[0],0),range.setEnd(triggerElements[triggerElements.length-1],1);rangeRef.current=range}},[triggerElements,selectedRange,positionAtStart]);let[tooltipVisible,setTooltipVisible]=useState(!1),toggleVisibility=useCallback(status=>{setTooltipVisible(status),onVisibilityChange&&onVisibilityChange(status)},[onVisibilityChange]);useEffect(()=>{selectedRange&&toggleVisibility(!0)},[]);let hideTooltipAfterDelay=useCallback(()=>{hideTooltipTimeoutId.current=setTimeout(()=>{triggerHovered.current||isTooltipHovered.current||!tooltipVisible||toggleVisibility(!1)},200)},[toggleVisibility,tooltipVisible]),handleTriggerPointerEnter=useCallback(()=>{triggerHovered.current=!0,tooltipVisible||(clearTimeout(showTooltipTimeoutId.current),showTooltipTimeoutId.current=setTimeout(()=>{!tooltipVisible&&triggerHovered.current&&toggleVisibility(!0)},200))},[toggleVisibility,tooltipVisible]),handleTriggerPointerLeave=useCallback(()=>{clearTimeout(hideTooltipTimeoutId.current),triggerHovered.current=!1,hideTooltipAfterDelay()},[hideTooltipAfterDelay]);return(useEffect(()=>()=>{clearTimeout(showTooltipTimeoutId.current),clearTimeout(hideTooltipTimeoutId.current)},[]),useEffect(()=>(triggerElements.forEach(node=>{node.addEventListener("pointerenter",handleTriggerPointerEnter),node.addEventListener("pointerleave",handleTriggerPointerLeave)}),()=>{triggerElements.forEach(node=>{node.removeEventListener("pointerenter",handleTriggerPointerEnter),node.removeEventListener("pointerleave",handleTriggerPointerLeave)})}),[handleTriggerPointerEnter,handleTriggerPointerLeave,triggerElements]),useEffect(()=>{triggerElements.forEach(node=>{tooltipVisible?node.setAttribute("aria-describedby",tooltipId):node.removeAttribute("aria-describedby")})},[tooltipId,tooltipVisible,triggerElements]),rangeRef.current)?React.createElement(TooltipContent,{dataDSId:"UserHighlightTooltip",content:content,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,isVisible:tooltipVisible,tooltipId:tooltipId,triggerRef:rangeRef,role:"tooltip",contentPadding:contentPadding,maxWidth:maxWidth,subTheme:"inverted",onTooltipPointerEnter:()=>{isTooltipHovered.current=!0},onTooltipPointerLeave:()=>{clearTimeout(hideTooltipTimeoutId.current),isTooltipHovered.current=!1,hideTooltipAfterDelay()}}):null}
1
+ import React,{useCallback,useEffect,useId,useMemo,useRef,useState}from"react";import{TooltipContent}from"../Tooltip/TooltipContent";import{findOverlappingTooltips}from"./-utils.ts/findOverlappingTooltips";import{getTopmostElement}from"./-utils.ts/getTopmostElement";import{TooltipRegistry}from"./-utils.ts/TooltipRegistry";let tooltipRegistry=new TooltipRegistry;export function UserHighlightTooltip({content,contentPadding="s",placement="auto",maxWidth,portalContainer,"data-e2e-test-id":dataE2eTestId,triggerElements,selectedRange,onVisibilityChange,positionAtStart}){let tooltipId=useMemo(()=>`DSUserHighlightTooltip_${Math.floor(Date.now()*Math.random())}`,[]),instanceId=useId(),isTooltipHovered=useRef(!1),showTooltipTimeoutId=useRef(null),hideTooltipTimeoutId=useRef(null),triggerHovered=useRef(!1),rangeRef=useRef(null);useEffect(()=>{if(selectedRange)rangeRef.current=selectedRange;else{let range=document.createRange();if(positionAtStart){let text=triggerElements[0].childNodes[0];range.setStart(text,0),range.setEnd(text,1)}else range.setStart(triggerElements[0],0),range.setEnd(triggerElements[triggerElements.length-1],1);rangeRef.current=range}},[triggerElements,selectedRange,positionAtStart]);let[tooltipVisible,setTooltipVisible]=useState(!1),toggleVisibility=useCallback(status=>{setTooltipVisible(status),onVisibilityChange&&onVisibilityChange(status)},[onVisibilityChange]);useEffect(()=>(tooltipRegistry.set(instanceId,{id:instanceId,triggerElements,setVisible:visible=>{setTooltipVisible(visible),onVisibilityChange&&onVisibilityChange(visible)}}),()=>{tooltipRegistry.delete(instanceId)}),[instanceId,triggerElements,onVisibilityChange]),useEffect(()=>{selectedRange&&toggleVisibility(!0)},[]);let hideTooltipAfterDelay=useCallback(()=>{hideTooltipTimeoutId.current=setTimeout(()=>{triggerHovered.current||isTooltipHovered.current||!tooltipVisible||toggleVisibility(!1)},200)},[toggleVisibility,tooltipVisible]),handleTriggerPointerEnter=useCallback(event=>{triggerHovered.current=!0,clearTimeout(showTooltipTimeoutId.current),showTooltipTimeoutId.current=setTimeout(()=>{if(triggerHovered.current){let overlappingTooltips=findOverlappingTooltips(event?.target||triggerElements[0],instanceId,tooltipRegistry);if(overlappingTooltips.length>0){let allOverlappingElements=[...triggerElements];overlappingTooltips.forEach(tooltip=>{allOverlappingElements.push(...tooltip.triggerElements)});let topmostElement=getTopmostElement(allOverlappingElements,event);!topmostElement||triggerElements.includes(topmostElement)?(overlappingTooltips.forEach(tooltip=>{tooltip.setVisible(!1)}),tooltipVisible||toggleVisibility(!0)):tooltipVisible&&toggleVisibility(!1)}else tooltipVisible||toggleVisibility(!0)}},200)},[toggleVisibility,tooltipVisible,triggerElements,instanceId]),handleTriggerPointerLeave=useCallback(event=>{if(clearTimeout(hideTooltipTimeoutId.current),triggerHovered.current=!1,event&&"clientX"in event&&"clientY"in event)try{let elementUnderPointer=document.elementFromPoint(event.clientX,event.clientY);if(elementUnderPointer){let overlappingTooltips=findOverlappingTooltips(elementUnderPointer,instanceId,tooltipRegistry);if(overlappingTooltips.length>0){let allOverlappingElements=[];overlappingTooltips.forEach(tooltip=>{allOverlappingElements.push(...tooltip.triggerElements)});let topmostElement=getTopmostElement(allOverlappingElements,event);if(topmostElement&&!triggerElements.includes(topmostElement)){toggleVisibility(!1);let enterEvent=new PointerEvent("pointerenter",{bubbles:!0,cancelable:!0,clientX:event.clientX,clientY:event.clientY,pointerId:event.pointerId,pointerType:event.pointerType});topmostElement.dispatchEvent(enterEvent);return}}}}catch{}hideTooltipAfterDelay()},[hideTooltipAfterDelay,instanceId,toggleVisibility,triggerElements]);return(useEffect(()=>()=>{clearTimeout(showTooltipTimeoutId.current),clearTimeout(hideTooltipTimeoutId.current)},[]),useEffect(()=>{let wrappedHandleEnter=event=>{handleTriggerPointerEnter(event)};return triggerElements.forEach(node=>{node.addEventListener("pointerenter",wrappedHandleEnter),node.addEventListener("pointerleave",handleTriggerPointerLeave)}),()=>{triggerElements.forEach(node=>{node.removeEventListener("pointerenter",wrappedHandleEnter),node.removeEventListener("pointerleave",handleTriggerPointerLeave)})}},[handleTriggerPointerEnter,handleTriggerPointerLeave,triggerElements]),useEffect(()=>{triggerElements.forEach(node=>{tooltipVisible?node.setAttribute("aria-describedby",tooltipId):node.removeAttribute("aria-describedby")})},[tooltipId,tooltipVisible,triggerElements]),rangeRef.current)?React.createElement(TooltipContent,{dataDSId:"UserHighlightTooltip",content:content,placement:placement,portalContainer:portalContainer,dataE2eTestId:dataE2eTestId,isVisible:tooltipVisible,tooltipId:tooltipId,triggerRef:rangeRef,role:"tooltip",contentPadding:contentPadding,maxWidth:maxWidth,subTheme:"inverted",onTooltipPointerEnter:()=>{isTooltipHovered.current=!0},onTooltipPointerLeave:()=>{clearTimeout(hideTooltipTimeoutId.current),isTooltipHovered.current=!1,hideTooltipAfterDelay()}}):null}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amboss/design-system",
3
- "version": "3.21.1",
3
+ "version": "3.21.2",
4
4
  "description": "the design system for AMBOSS products",
5
5
  "author": "AMBOSS",
6
6
  "license": "ISC",