Skip to content

Commit e214100

Browse files
committed
[chrome] ux: animate tab tooltip when hovering between tabs
1 parent 73f2a55 commit e214100

File tree

2 files changed

+64
-12
lines changed

2 files changed

+64
-12
lines changed

packages/chrome/src/components/TabStrip/DragTab.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import { setContextMenu } from "../Menu";
44
import { iconClose, iconDuplicate, iconNew, iconRefresh } from "../../icons";
55
import { browser, forceScreenshot } from "../../Browser";
66
import { Icon } from "../Icon";
7-
import { activeTooltips, TabTooltip } from "./TabTooltip";
7+
import { activeTooltips, fastClose, TabTooltip } from "./TabTooltip";
88

99
export function DragTab(
10-
this: { tooltipActive: boolean },
10+
this: {
11+
tooltipActive: boolean;
12+
tooltipAnimate: boolean;
13+
},
1114
props: {
1215
active: boolean;
1316
id: number;
@@ -95,6 +98,8 @@ export function DragTab(
9598

9699
if (activeTooltips > 0) {
97100
// skip delay
101+
fastClose();
102+
this.tooltipAnimate = true;
98103
this.tooltipActive = true;
99104
} else {
100105
hoverTimeout = window.setTimeout(() => {
@@ -112,7 +117,11 @@ export function DragTab(
112117
this.tooltipActive = false;
113118
}}
114119
></div>
115-
<TabTooltip tab={props.tab} active={use(this.tooltipActive)} />
120+
<TabTooltip
121+
tab={props.tab}
122+
active={use(this.tooltipActive)}
123+
animate={use(this.tooltipAnimate)}
124+
/>
116125
<div
117126
class="dragroot"
118127
style="position: unset;"
@@ -161,10 +170,10 @@ DragTab.style = css`
161170
162171
.hover-area {
163172
position: absolute;
164-
top: -5px;
173+
top: -3px;
165174
left: -3px;
166-
right: -5px;
167-
bottom: -5px;
175+
right: -3px;
176+
bottom: -3px;
168177
pointer-events: auto;
169178
}
170179

packages/chrome/src/components/TabStrip/TabTooltip.tsx

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
import { css, type ComponentContext } from "dreamland/core";
1+
import { createDelegate, css, type ComponentContext } from "dreamland/core";
22
import type { Tab } from "../../Tab";
33
import { isFirefox } from "../../utils";
44

55
export let activeTooltips = 0;
6+
export let lastX;
7+
8+
export const fastClose = createDelegate<void>();
69

710
export function TabTooltip(
8-
props: { active: boolean; tab: Tab },
11+
props: {
12+
active: boolean;
13+
animate: boolean;
14+
tab: Tab;
15+
},
916
cx: ComponentContext
1017
) {
1118
let wasActive = props.active;
@@ -20,20 +27,56 @@ export function TabTooltip(
2027
transform: "scale(95%)",
2128
};
2229

30+
let isClosing = false;
31+
fastClose.listen(() => {
32+
if (isClosing) {
33+
// instantly finish any current animations
34+
let animations = cx.root.getAnimations();
35+
for (let anim of animations) {
36+
anim.finish();
37+
}
38+
}
39+
});
40+
2341
use(props.active).listen((active) => {
2442
if (active && !wasActive) {
2543
wasActive = true;
2644
activeTooltips++;
27-
cx.root.animate([hidden, visible], {
28-
duration,
29-
fill: "forwards",
30-
});
45+
46+
let x = cx.root.getBoundingClientRect().left;
47+
48+
if (props.animate) {
49+
let shift = lastX - x;
50+
cx.root.animate([hidden, visible], {
51+
duration: 0,
52+
fill: "forwards",
53+
});
54+
cx.root.animate(
55+
[
56+
{ transform: `translateX(${shift}px)` },
57+
{ transform: "translateX(0px)" },
58+
],
59+
{
60+
duration: 300,
61+
easing: "ease-out",
62+
}
63+
);
64+
props.animate = false;
65+
} else {
66+
cx.root.animate([hidden, visible], {
67+
duration,
68+
fill: "forwards",
69+
});
70+
}
71+
lastX = x;
3172
} else if (!active && wasActive) {
3273
wasActive = false;
74+
isClosing = true;
3375
cx.root.animate([visible, hidden], {
3476
duration,
3577
fill: "forwards",
3678
}).onfinish = () => {
79+
isClosing = false;
3780
activeTooltips--;
3881
};
3982
}

0 commit comments

Comments
 (0)