From c39b1f8809c235d3ce1c9a083cf3252db17bcfa7 Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Sat, 14 Mar 2026 19:34:33 +1100 Subject: [PATCH] fix: add popover and tooltip safe areas (#951) --- .../src/default/css/components/popup.css | 49 ++++++++++++++++++ .../src/default/tailwind/components/popup.ts | 19 +++++-- .../src/minimal/css/components/popup.css | 51 +++++++++++++++++++ .../src/minimal/tailwind/audio.tailwind.ts | 1 + .../src/minimal/tailwind/components/popup.ts | 19 ++++++- .../src/minimal/tailwind/video.tailwind.ts | 2 +- 6 files changed, 135 insertions(+), 6 deletions(-) diff --git a/packages/skins/src/default/css/components/popup.css b/packages/skins/src/default/css/components/popup.css index 15f5fce9..6f667888 100644 --- a/packages/skins/src/default/css/components/popup.css +++ b/packages/skins/src/default/css/components/popup.css @@ -34,10 +34,50 @@ &[data-side="right"] { transform-origin: left; } + + /* Safe area between trigger and popup */ + &::before { + content: ""; + position: absolute; + pointer-events: inherit; + } + + &[data-side="top"]::before, + &[data-side="bottom"]::before { + width: 100%; + inset-inline: 0; + } + &[data-side="top"]::before { + top: 100%; + } + &[data-side="bottom"]::before { + bottom: 100%; + } + + &[data-side="left"]::before, + &[data-side="right"]::before { + height: 100%; + inset-block: 0; + } + &[data-side="left"]::before { + left: 100%; + } + &[data-side="right"]::before { + right: 100%; + } } .media-default-skin .media-popover { --media-popover-side-offset: 0.5rem; + + &[data-side="top"]::before, + &[data-side="bottom"]::before { + height: var(--media-popover-side-offset); + } + &[data-side="left"]::before, + &[data-side="right"]::before { + width: var(--media-popover-side-offset); + } } .media-default-skin .media-popover--volume { padding: 0.625rem 0.25rem; @@ -50,4 +90,13 @@ font-size: 0.75rem; white-space: nowrap; --media-tooltip-side-offset: 0.75rem; + + &[data-side="top"]::before, + &[data-side="bottom"]::before { + height: var(--media-tooltip-side-offset); + } + &[data-side="left"]::before, + &[data-side="right"]::before { + width: var(--media-tooltip-side-offset); + } } diff --git a/packages/skins/src/default/tailwind/components/popup.ts b/packages/skins/src/default/tailwind/components/popup.ts index 163d147d..8c9d0f53 100644 --- a/packages/skins/src/default/tailwind/components/popup.ts +++ b/packages/skins/src/default/tailwind/components/popup.ts @@ -9,15 +9,28 @@ const base = cn( 'data-ending-style:opacity-0 data-ending-style:scale-50 data-ending-style:blur-sm', 'data-instant:duration-0', // Ensure we animate from the correct origin based on the side the popover is on - 'data-[side=top]:origin-bottom data-[side=bottom]:origin-top data-[side=left]:origin-right data-[side=right]:origin-left' + 'data-[side=top]:origin-bottom data-[side=bottom]:origin-top data-[side=left]:origin-right data-[side=right]:origin-left', + // Safe area between trigger and popup + 'before:absolute before:pointer-events-[inherit]', + 'data-[side=top]:before:left-0 data-[side=top]:before:right-0 data-[side=top]:before:top-full', + 'data-[side=bottom]:before:left-0 data-[side=bottom]:before:right-0 data-[side=bottom]:before:bottom-full', + 'data-[side=left]:before:top-0 data-[side=left]:before:bottom-0 data-[side=left]:before:left-full', + 'data-[side=right]:before:top-0 data-[side=right]:before:bottom-0 data-[side=right]:before:right-full' ); export const popup = { - popover: cn(base, '[--media-popover-side-offset:0.5rem]'), + popover: cn( + base, + '[--media-popover-side-offset:0.5rem]', + 'data-[side=top]:before:h-(--media-popover-side-offset) data-[side=bottom]:before:h-(--media-popover-side-offset)', + 'data-[side=left]:before:w-(--media-popover-side-offset) data-[side=right]:before:w-(--media-popover-side-offset)' + ), tooltip: cn( base, 'py-1 px-2.5 rounded-full text-[0.75rem] whitespace-nowrap', - '[--media-tooltip-side-offset:0.75rem]' + '[--media-tooltip-side-offset:0.75rem]', + 'data-[side=top]:before:h-(--media-tooltip-side-offset) data-[side=bottom]:before:h-(--media-tooltip-side-offset)', + 'data-[side=left]:before:w-(--media-tooltip-side-offset) data-[side=right]:before:w-(--media-tooltip-side-offset)' ), volume: 'py-2.5 px-1 rounded-full', }; diff --git a/packages/skins/src/minimal/css/components/popup.css b/packages/skins/src/minimal/css/components/popup.css index 09a70ef7..6145f885 100644 --- a/packages/skins/src/minimal/css/components/popup.css +++ b/packages/skins/src/minimal/css/components/popup.css @@ -34,6 +34,48 @@ &[data-side="right"] { transform-origin: left; } + + /* Safe area between trigger and popup */ + &::before { + content: ""; + position: absolute; + pointer-events: inherit; + } + + &[data-side="top"]::before, + &[data-side="bottom"]::before { + width: 100%; + inset-inline: 0; + } + &[data-side="top"]::before { + top: 100%; + } + &[data-side="bottom"]::before { + bottom: 100%; + } + + &[data-side="left"]::before, + &[data-side="right"]::before { + height: 100%; + inset-block: 0; + } + &[data-side="left"]::before { + left: 100%; + } + &[data-side="right"]::before { + right: 100%; + } +} + +.media-minimal-skin .media-popover { + &[data-side="top"]::before, + &[data-side="bottom"]::before { + height: var(--media-popover-side-offset); + } + &[data-side="left"]::before, + &[data-side="right"]::before { + width: var(--media-popover-side-offset); + } } .media-minimal-skin .media-tooltip { @@ -48,6 +90,15 @@ white-space: nowrap; --media-tooltip-side-offset: 0.75rem; + &[data-side="top"]::before, + &[data-side="bottom"]::before { + height: var(--media-tooltip-side-offset); + } + &[data-side="left"]::before, + &[data-side="right"]::before { + width: var(--media-tooltip-side-offset); + } + @media (prefers-reduced-transparency: reduce) { background-color: oklch(0 0 0 / 0.7); } diff --git a/packages/skins/src/minimal/tailwind/audio.tailwind.ts b/packages/skins/src/minimal/tailwind/audio.tailwind.ts index dc45f0ca..3d7cf94d 100644 --- a/packages/skins/src/minimal/tailwind/audio.tailwind.ts +++ b/packages/skins/src/minimal/tailwind/audio.tailwind.ts @@ -42,6 +42,7 @@ export const controls = cn( export const popup = { ...basePopup, volume: cn( + basePopup.popover, 'py-2 pr-0 pl-16', 'bg-transparent bg-gradient-to-l from-(--media-controls-background-color) from-80% to-transparent', '[--media-popover-side-offset:0.75rem]' diff --git a/packages/skins/src/minimal/tailwind/components/popup.ts b/packages/skins/src/minimal/tailwind/components/popup.ts index b94a2b6e..cb5c41e3 100644 --- a/packages/skins/src/minimal/tailwind/components/popup.ts +++ b/packages/skins/src/minimal/tailwind/components/popup.ts @@ -9,14 +9,29 @@ const base = cn( 'data-ending-style:opacity-0 data-ending-style:scale-50 data-ending-style:blur-sm', 'data-instant:duration-0', // Ensure we animate from the correct origin based on the side the popover is on - 'data-[side=top]:origin-bottom data-[side=bottom]:origin-top data-[side=left]:origin-right data-[side=right]:origin-left' + 'data-[side=top]:origin-bottom data-[side=bottom]:origin-top data-[side=left]:origin-right data-[side=right]:origin-left', + // Safe area between trigger and popup + 'before:absolute before:pointer-events-[inherit]', + 'data-[side=top]:before:left-0 data-[side=top]:before:right-0 data-[side=top]:before:top-full', + 'data-[side=bottom]:before:left-0 data-[side=bottom]:before:right-0 data-[side=bottom]:before:bottom-full', + 'data-[side=left]:before:top-0 data-[side=left]:before:bottom-0 data-[side=left]:before:left-full', + 'data-[side=right]:before:top-0 data-[side=right]:before:bottom-0 data-[side=right]:before:right-full' ); export const popup = { base, + popover: cn( + base, + 'data-[side=top]:before:h-(--media-popover-side-offset) data-[side=bottom]:before:h-(--media-popover-side-offset)', + 'data-[side=left]:before:w-(--media-popover-side-offset) data-[side=right]:before:w-(--media-popover-side-offset)' + ), tooltip: cn( base, 'px-2 py-1 rounded-sm shadow-md shadow-black/10 bg-white/10 backdrop-blur-lg backdrop-saturate-150 text-[0.75rem] whitespace-nowrap', - '[--media-tooltip-side-offset:0.75rem]' + '[--media-tooltip-side-offset:0.75rem]', + 'data-[side=top]:before:h-(--media-tooltip-side-offset) data-[side=bottom]:before:h-(--media-tooltip-side-offset)', + 'data-[side=left]:before:w-(--media-tooltip-side-offset) data-[side=right]:before:w-(--media-tooltip-side-offset)', + '[@media(prefers-reduced-transparency:reduce)]:bg-black/70', + 'contrast-more:bg-black/90' ), }; diff --git a/packages/skins/src/minimal/tailwind/video.tailwind.ts b/packages/skins/src/minimal/tailwind/video.tailwind.ts index 416b5b49..a11ccaa8 100644 --- a/packages/skins/src/minimal/tailwind/video.tailwind.ts +++ b/packages/skins/src/minimal/tailwind/video.tailwind.ts @@ -124,7 +124,7 @@ export const slider = { export const popup = { ...basePopup, - volume: cn(basePopup.base, '[--media-popover-side-offset:0.5rem] p-1 bg-transparent'), + volume: cn(basePopup.popover, '[--media-popover-side-offset:0.5rem] p-1 bg-transparent'), }; /* ==========================================================================