Skip to content

Commit 94de425

Browse files
Apply PR #38403: fix(ui): standardize v2 tooltip delay
2 parents ee771df + f77f5a3 commit 94de425

10 files changed

Lines changed: 81 additions & 29 deletions

File tree

packages/app/src/components/dialog-select-model-unpaid-v2.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export const DialogSelectModelUnpaidV2: Component<{ model?: ModelState }> = (pro
8888
class="w-full"
8989
placement="right-start"
9090
gutter={6}
91-
openDelay={0}
91+
delay="intent"
9292
contentStyle={{ "font-family": "var(--v2-font-family-sans)" }}
9393
value={
9494
<ModelTooltip

packages/app/src/components/dialog-select-model.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ function ModelSelectorPopoverV2View(props: {
460460
class="w-full"
461461
placement="right-start"
462462
gutter={6}
463-
openDelay={0}
463+
delay="intent"
464464
value={
465465
<ModelTooltip
466466
model={item}

packages/app/src/components/prompt-input/context-items.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const PromptContextItems: Component<ContextItemsProps> = (props) => {
4747
</span>
4848
}
4949
placement="top"
50-
openDelay={800}
50+
{...(!props.newLayoutDesigns ? { openDelay: 800 } : {})}
5151
>
5252
<div
5353
classList={{

packages/app/src/components/prompt-input/image-attachments.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,7 @@ export const PromptImageAttachments: Component<PromptImageAttachmentsProps> = (p
5252
<For each={props.comments ?? []}>
5353
{(item) => (
5454
<div class="relative group shrink-0">
55-
<TooltipV2
56-
value={item.comment}
57-
placement="top"
58-
openDelay={800}
59-
contentClass="max-w-[300px] break-words"
60-
>
55+
<TooltipV2 value={item.comment} placement="top" contentClass="max-w-[300px] break-words">
6156
<CommentCardV2
6257
comment={item.comment ?? ""}
6358
path={item.path}

packages/app/src/pages/new-session/new-session-view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ function ProviderTip() {
143143
<TooltipV2
144144
class="hover-reveal absolute left-full top-0 flex h-6 w-7 items-center justify-end delay-0 duration-0 group-hover/provider-tip:delay-[250ms] group-hover/provider-tip:duration-150 group-hover/provider-tip:opacity-100 focus-within:delay-0 focus-within:duration-0 focus-within:opacity-100"
145145
placement="top"
146-
openDelay={1000}
146+
delay="intent"
147147
value={language.t("common.dismiss")}
148148
>
149149
<button

packages/session-ui/src/v2/components/comment-card-v2.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export function CommentCardV2(props: {
3232
return (
3333
<TooltipV2
3434
placement="top"
35-
openDelay={1000}
3635
value={props.title ?? props.comment}
3736
disabled={!props.tooltip || !truncated()}
3837
class={props.wide ? "w-full" : undefined}

packages/session-ui/src/v2/components/prompt-input/index.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,7 @@ export function PromptInputV2Attachments(props: {
387387
<For each={props.comments ?? []}>
388388
{(comment) => (
389389
<div class="relative group shrink-0">
390-
<TooltipV2
391-
value={comment.comment}
392-
placement="top"
393-
openDelay={800}
394-
contentClass="max-w-[300px] break-words"
395-
>
390+
<TooltipV2 value={comment.comment} placement="top" contentClass="max-w-[300px] break-words">
396391
<CommentCardV2
397392
comment={comment.comment ?? ""}
398393
path={comment.path}

packages/session-ui/src/v2/components/session-review-v2.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,6 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
216216
</Show>
217217
<div class="flex items-center">
218218
<TooltipV2
219-
openDelay={2000}
220219
inactive={!prev()}
221220
value={
222221
<>
@@ -236,7 +235,6 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
236235
/>
237236
</TooltipV2>
238237
<TooltipV2
239-
openDelay={2000}
240238
inactive={!next()}
241239
value={
242240
<>
@@ -270,12 +268,12 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
270268
class="session-review-v2-segmented-control session-review-v2-segmented-control--icon"
271269
aria-label={i18n.t("ui.sessionReviewV2.expandMode")}
272270
>
273-
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.showAllLines")}>
271+
<TooltipV2 value={i18n.t("ui.sessionReviewV2.showAllLines")}>
274272
<SegmentedControlItemV2 value="expand" aria-label={i18n.t("ui.sessionReviewV2.showAllLines")}>
275273
<Icon name="expand" />
276274
</SegmentedControlItemV2>
277275
</TooltipV2>
278-
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
276+
<TooltipV2 value={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
279277
<SegmentedControlItemV2 value="collapse" aria-label={i18n.t("ui.sessionReviewV2.hideNonDiffLines")}>
280278
<Icon name="collapse" />
281279
</SegmentedControlItemV2>
@@ -291,12 +289,12 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
291289
class="session-review-v2-segmented-control session-review-v2-segmented-control--icon"
292290
aria-label={i18n.t("ui.sessionReviewV2.diffView")}
293291
>
294-
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
292+
<TooltipV2 value={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
295293
<SegmentedControlItemV2 value="unified" aria-label={i18n.t("ui.sessionReviewV2.unifiedDiff")}>
296294
<Icon name="unified" />
297295
</SegmentedControlItemV2>
298296
</TooltipV2>
299-
<TooltipV2 openDelay={2000} value={i18n.t("ui.sessionReviewV2.splitDiff")}>
297+
<TooltipV2 value={i18n.t("ui.sessionReviewV2.splitDiff")}>
300298
<SegmentedControlItemV2 value="split" aria-label={i18n.t("ui.sessionReviewV2.splitDiff")}>
301299
<Icon name="split" />
302300
</SegmentedControlItemV2>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const OPEN_DELAY = 1_000
2+
3+
// Kobalte warms every tooltip globally. Keep intent previews isolated so opening
4+
// a model picker never inherits warm state from an unrelated tooltip.
5+
let warm = false
6+
let reset: ReturnType<typeof setTimeout> | undefined
7+
8+
export function openTooltipIntent(open: () => void) {
9+
clearTimeout(reset)
10+
reset = undefined
11+
if (warm) {
12+
open()
13+
return
14+
}
15+
const timer = setTimeout(() => {
16+
warm = true
17+
open()
18+
}, OPEN_DELAY)
19+
return () => clearTimeout(timer)
20+
}
21+
22+
export function closeTooltipIntent() {
23+
clearTimeout(reset)
24+
// Adjacent triggers enter before the next task; leaving the group does not.
25+
reset = setTimeout(() => {
26+
warm = false
27+
reset = undefined
28+
})
29+
}
30+
31+
export function resetTooltipIntent() {
32+
clearTimeout(reset)
33+
reset = undefined
34+
warm = false
35+
}

packages/ui/src/v2/components/tooltip-v2.tsx

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@ import { Tooltip as KobalteTooltip } from "@kobalte/core/tooltip"
22
import { createEffect, Match, onCleanup, splitProps, Switch, type JSX } from "solid-js"
33
import type { ComponentProps } from "solid-js"
44
import { createStore } from "solid-js/store"
5+
import { closeTooltipIntent, openTooltipIntent, resetTooltipIntent } from "./tooltip-intent"
56
import "./tooltip-v2.css"
67

7-
export interface TooltipV2Props extends ComponentProps<typeof KobalteTooltip> {
8+
export interface TooltipV2Props extends Omit<ComponentProps<typeof KobalteTooltip>, "openDelay"> {
89
value: JSX.Element
910
class?: string
1011
contentClass?: string
1112
contentStyle?: JSX.CSSProperties
1213
inactive?: boolean
14+
delay?: "standard" | "intent"
1315
forceOpen?: boolean
1416
}
1517

1618
export function TooltipV2(props: TooltipV2Props) {
1719
let ref: HTMLDivElement | undefined
20+
let cancelIntent: (() => void) | undefined
1821
const [state, setState] = createStore({
1922
open: false,
2023
block: false,
@@ -26,19 +29,37 @@ export function TooltipV2(props: TooltipV2Props) {
2629
"contentClass",
2730
"contentStyle",
2831
"inactive",
32+
"delay",
2933
"forceOpen",
3034
"ignoreSafeArea",
3135
"value",
3236
])
3337

34-
const close = () => setState("open", false)
35-
3638
const inside = () => {
3739
const active = document.activeElement
3840
if (!ref || !active) return false
3941
return ref.contains(active)
4042
}
4143

44+
const close = () => {
45+
cancelIntent?.()
46+
cancelIntent = undefined
47+
if (local.delay === "intent") closeTooltipIntent()
48+
setState("open", false)
49+
}
50+
51+
const show = () => {
52+
if (local.delay !== "intent" || inside()) {
53+
setState("open", true)
54+
return
55+
}
56+
if (cancelIntent) return
57+
cancelIntent = openTooltipIntent(() => {
58+
cancelIntent = undefined
59+
setState("open", true)
60+
})
61+
}
62+
4263
const drop = (expand = state.expand) => {
4364
if (expand) return
4465
if (ref?.matches(":hover")) return
@@ -80,6 +101,11 @@ export function TooltipV2(props: TooltipV2Props) {
80101
onCleanup(() => obs.disconnect())
81102
})
82103

104+
onCleanup(() => {
105+
cancelIntent?.()
106+
if (local.delay === "intent") resetTooltipIntent()
107+
})
108+
83109
let justClickedTrigger = false
84110

85111
return (
@@ -88,8 +114,8 @@ export function TooltipV2(props: TooltipV2Props) {
88114
<Match when={true}>
89115
<KobalteTooltip
90116
gutter={4}
91-
openDelay={400}
92-
skipDelayDuration={300}
117+
openDelay={local.delay === "intent" ? 0 : 400}
118+
skipDelayDuration={local.delay === "intent" ? 0 : 300}
93119
{...others}
94120
closeDelay={0}
95121
ignoreSafeArea={local.ignoreSafeArea ?? true}
@@ -101,7 +127,11 @@ export function TooltipV2(props: TooltipV2Props) {
101127
justClickedTrigger = false
102128
return
103129
}
104-
setState("open", open)
130+
if (open) {
131+
show()
132+
return
133+
}
134+
close()
105135
}}
106136
>
107137
<KobalteTooltip.Trigger

0 commit comments

Comments
 (0)