diff --git a/.changeset/red-lies-lick.md b/.changeset/red-lies-lick.md new file mode 100644 index 0000000000..fef1be59aa --- /dev/null +++ b/.changeset/red-lies-lick.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': patch +--- + +Fixed an issue related to conflicting pointer and focus events hiding the tooltip unexpectedly in some situations. The tooltip now behaves as expected in this situation. diff --git a/packages/components/src/components.d.ts b/packages/components/src/components.d.ts index a01163268d..162398245b 100644 --- a/packages/components/src/components.d.ts +++ b/packages/components/src/components.d.ts @@ -311,8 +311,9 @@ export namespace Components { /** * Programmatically display the tooltip * @param target An element with [data-tooltip-target="id"] where the tooltip should be shown + * @param triggeredByFocus A boolean indicating if the tooltip was triggered by a focus event. */ - "show": (target: HTMLElement) => Promise; + "show": (target: HTMLElement, triggeredByFocus?: boolean) => Promise; /** * Toggle tooltip display * @param target An element with [data-tooltip-target="id"] where the tooltip should be shown diff --git a/packages/components/src/components/post-tooltip/post-tooltip.tsx b/packages/components/src/components/post-tooltip/post-tooltip.tsx index 5a7f2fe549..2ce0237ac7 100644 --- a/packages/components/src/components/post-tooltip/post-tooltip.tsx +++ b/packages/components/src/components/post-tooltip/post-tooltip.tsx @@ -23,6 +23,10 @@ const tooltipTargetAttributeSelector = `[${tooltipTargetAttribute}]`; /** * Global event listener to show tooltips. This is globalized so that triggers that are rendered * async will still work without the need to set listeners on the element itself + * + * This handler manages both pointer and focus events to properly trigger tooltips. + * If the event is a focus event (e.g., keyboard navigation), pointer events are ignored to avoid + * interference with tooltip behavior. * @param e Event * @returns */ @@ -34,7 +38,11 @@ const globalInterestHandler = (e: PointerEvent | FocusEvent) => { const tooltipTarget = targetElement.getAttribute(tooltipTargetAttribute); if (!tooltipTarget || tooltipTarget === '') return; const tooltip = document.getElementById(tooltipTarget) as HTMLPostTooltipElement; - void tooltip?.show(targetElement); + + // Determine if the tooltip was triggered by a focus event + const triggeredByFocus = e.type === 'focusin'; + void tooltip?.show(targetElement, triggeredByFocus); + if (hideTooltipTimeout) { window.clearTimeout(hideTooltipTimeout); hideTooltipTimeout = null; @@ -98,6 +106,7 @@ const triggerObserver = getAttributeObserver(tooltipTargetAttribute, patchAccess }) export class PostTooltip { private popoverRef: HTMLPostPopovercontainerElement; + private wasOpenedByFocus: boolean = false; @Element() host: HTMLPostTooltipElement; @@ -186,10 +195,22 @@ export class PostTooltip { /** * Programmatically display the tooltip * @param target An element with [data-tooltip-target="id"] where the tooltip should be shown + * @param triggeredByFocus A boolean indicating if the tooltip was triggered by a focus event. */ @Method() - async show(target: HTMLElement) { + async show(target: HTMLElement, triggeredByFocus = false) { if (this.delayed) await timeout(OPEN_DELAY); + + // Determine if the tooltip was opened by a focus event + this.wasOpenedByFocus = triggeredByFocus; + + // Disable pointer events if triggered by focus, otherwise enable them + if (this.wasOpenedByFocus) { + this.host.style.pointerEvents = 'none'; + } else { + this.host.style.pointerEvents = 'auto'; + } + this.popoverRef.show(target); } @@ -223,9 +244,11 @@ export class PostTooltip { /** * Pointer or focus left the tooltip, initiate the hiding process + * Re-enable pointer events when the tooltip is no longer in focus or hovered */ private handleInterestLost() { globalHideTooltip(this); + this.host.style.pointerEvents = 'auto'; } render() { diff --git a/packages/components/src/components/post-tooltip/readme.md b/packages/components/src/components/post-tooltip/readme.md index 215b2f07f9..4fd194c2fa 100644 --- a/packages/components/src/components/post-tooltip/readme.md +++ b/packages/components/src/components/post-tooltip/readme.md @@ -26,15 +26,16 @@ Type: `Promise` -### `show(target: HTMLElement) => Promise` +### `show(target: HTMLElement, triggeredByFocus?: boolean) => Promise` Programmatically display the tooltip #### Parameters -| Name | Type | Description | -| -------- | ------------- | ---------------------------------------------------------------------------- | -| `target` | `HTMLElement` | An element with [data-tooltip-target="id"] where the tooltip should be shown | +| Name | Type | Description | +| ------------------ | ------------- | ---------------------------------------------------------------------------- | +| `target` | `HTMLElement` | An element with [data-tooltip-target="id"] where the tooltip should be shown | +| `triggeredByFocus` | `boolean` | A boolean indicating if the tooltip was triggered by a focus event. | #### Returns diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a19e5b49e3..c479524049 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10947,7 +10947,7 @@ snapshots: '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.3.2(@types/node@20.12.7)(less@4.2.0)(sass@1.77.6)(terser@5.29.2)) ansi-colors: 4.1.3 autoprefixer: 10.4.19(postcss@8.4.38) - babel-loader: 9.1.3(@babel/core@7.24.7)(webpack@5.92.1) + babel-loader: 9.1.3(@babel/core@7.24.7)(webpack@5.92.1(esbuild@0.21.5)) browserslist: 4.23.2 copy-webpack-plugin: 12.0.2(webpack@5.92.1(esbuild@0.21.5)) critters: 0.0.24 @@ -11040,7 +11040,7 @@ snapshots: '@vitejs/plugin-basic-ssl': 1.1.0(vite@5.3.2(@types/node@20.14.14)(less@4.2.0)(sass@1.77.6)(terser@5.29.2)) ansi-colors: 4.1.3 autoprefixer: 10.4.19(postcss@8.4.38) - babel-loader: 9.1.3(@babel/core@7.24.7)(webpack@5.92.1) + babel-loader: 9.1.3(@babel/core@7.24.7)(webpack@5.92.1(esbuild@0.21.5)) browserslist: 4.23.2 copy-webpack-plugin: 12.0.2(webpack@5.92.1(esbuild@0.21.5)) critters: 0.0.24 @@ -15867,7 +15867,7 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.92.1): + babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.92.1(esbuild@0.21.5)): dependencies: '@babel/core': 7.24.7 find-cache-dir: 4.0.0