@@ -10,26 +10,30 @@ import androidx.compose.runtime.Composable
1010import androidx.compose.runtime.getValue
1111import androidx.compose.runtime.mutableStateOf
1212import androidx.compose.runtime.remember
13+ import androidx.compose.runtime.rememberCoroutineScope
1314import androidx.compose.runtime.setValue
14- import androidx.compose.ui.Alignment
1515import androidx.compose.ui.ExperimentalComposeUiApi
1616import androidx.compose.ui.Modifier
1717import androidx.compose.ui.draw.clip
1818import androidx.compose.ui.draw.shadow
1919import androidx.compose.ui.graphics.graphicsLayer
20- import androidx.compose.ui.input.pointer.PointerEventPass
2120import androidx.compose.ui.input.pointer.PointerEventType
2221import androidx.compose.ui.input.pointer.PointerType
2322import androidx.compose.ui.input.pointer.pointerInput
23+ import androidx.compose.ui.platform.LocalDensity
2424import androidx.compose.ui.text.TextStyle
2525import androidx.compose.ui.tooling.preview.Preview
2626import androidx.compose.ui.unit.IntOffset
27+ import androidx.compose.ui.unit.IntRect
28+ import androidx.compose.ui.unit.IntSize
29+ import androidx.compose.ui.unit.LayoutDirection
2730import androidx.compose.ui.unit.dp
2831import androidx.compose.ui.window.Popup
32+ import androidx.compose.ui.window.PopupPositionProvider
2933import androidx.compose.ui.window.PopupProperties
3034import io.github.kdroidfilter.nucleus.ui.apple.macos.components.Text
3135import io.github.kdroidfilter.nucleus.ui.apple.macos.theme.MacosTheme
32- import kotlinx.coroutines.coroutineScope
36+ import kotlinx.coroutines.Job
3337import kotlinx.coroutines.delay
3438import kotlinx.coroutines.launch
3539
@@ -61,39 +65,57 @@ fun Tooltip(
6165 val colors = MacosTheme .colorScheme
6266 val typography = MacosTheme .typography
6367 val shapes = MacosTheme .shapes
68+ val density = LocalDensity .current
69+ val scope = rememberCoroutineScope()
6470
6571 var showTooltip by remember { mutableStateOf(false ) }
72+ var hoverJob: Job ? by remember { mutableStateOf(null ) }
6673
67- // Fade animation
6874 val alpha by animateFloatAsState(
6975 targetValue = if (showTooltip) 1f else 0f ,
7076 animationSpec = tween(durationMillis = 100 ),
7177 label = " tooltipAlpha" ,
7278 )
7379
74- // Tooltip colors: inverted from current theme
7580 val tooltipBackground = colors.inverseSurface
76-
7781 val tooltipTextColor = colors.inverseOnSurface
7882
83+ val gapPx = with (density) { 4 .dp.roundToPx() }
84+ val positionProvider = remember(gapPx) {
85+ object : PopupPositionProvider {
86+ override fun calculatePosition (
87+ anchorBounds : IntRect ,
88+ windowSize : IntSize ,
89+ layoutDirection : LayoutDirection ,
90+ popupContentSize : IntSize ,
91+ ): IntOffset = IntOffset (
92+ x = (anchorBounds.left + (anchorBounds.width - popupContentSize.width) / 2 )
93+ .coerceIn(0 , (windowSize.width - popupContentSize.width).coerceAtLeast(0 )),
94+ y = anchorBounds.top - popupContentSize.height - gapPx,
95+ )
96+ }
97+ }
98+
7999 Box (
80100 modifier = modifier
81101 .pointerInput(Unit ) {
82- coroutineScope {
83- awaitPointerEventScope {
84- val pass = PointerEventPass . Main
85- while ( true ) {
86- val event = awaitPointerEvent(pass)
87- val inputType = event.changes.firstOrNull()?. type
88- if (inputType == PointerType . Mouse ) {
89- when (event.type) {
90- PointerEventType . Enter -> launch {
102+ awaitPointerEventScope {
103+ while ( true ) {
104+ val event = awaitPointerEvent()
105+ val inputType = event.changes.firstOrNull()?.type
106+ if (inputType == PointerType . Mouse ) {
107+ when ( event.type) {
108+ PointerEventType . Enter -> {
109+ hoverJob?.cancel()
110+ hoverJob = scope. launch {
91111 delay(delayMillis)
92112 showTooltip = true
93113 }
94- PointerEventType .Exit -> {
95- showTooltip = false
96- }
114+ }
115+ PointerEventType .Exit -> {
116+ hoverJob?.cancel()
117+ hoverJob = null
118+ showTooltip = false
97119 }
98120 }
99121 }
@@ -105,11 +127,8 @@ fun Tooltip(
105127
106128 if (showTooltip || alpha > 0f ) {
107129 Popup (
108- alignment = Alignment .TopCenter ,
109- offset = IntOffset (0 , - 8 ),
110- properties = PopupProperties (
111- focusable = false ,
112- ),
130+ popupPositionProvider = positionProvider,
131+ properties = PopupProperties (focusable = false ),
113132 ) {
114133 Box (
115134 modifier = Modifier
0 commit comments