Replace text-only tooltips with custom richly styled tooltips (#3436)

* Replace the title attribute with custom FloatingMenu tooltips

* Separate tooltip labels and descriptions into two styled blocks

* Move keyboard shortcut tooltips to a separate section at the bottom

* Update shortcut key styling in tooltips and hints bar

* Fix .to_string()
This commit is contained in:
Keavon Chambers
2025-11-30 13:32:58 -08:00
committed by GitHub
parent 94e5c8fc05
commit e8ebcc2c21
94 changed files with 1323 additions and 580 deletions
+64
View File
@@ -0,0 +1,64 @@
import { writable } from "svelte/store";
const SHOW_TOOLTIP_DELAY_MS = 500;
export function createTooltipState() {
const { subscribe, update } = writable({
visible: false,
element: undefined as Element | undefined,
position: { x: 0, y: 0 },
});
let tooltipTimeout: ReturnType<typeof setTimeout> | undefined = undefined;
// Listen for mouse movements onto tooltip-bearing HTML elements to track the future target of a tooltip
document.addEventListener("mouseover", (e) => {
const element = (e.target instanceof Element && e.target.closest("[data-tooltip-label], [data-tooltip-description], [data-tooltip-shortcut]")) || undefined;
update((state) => {
state.visible = false;
state.element = element;
return state;
});
});
// Listen for mouse movements to schedule and position the tooltip, or hide it immediately upon further movement
document.addEventListener("mousemove", (e) => {
// Hide the tooltip now that the cursor has moved
update((state) => {
state.visible = false;
return state;
});
// Before we schedule a new future tooltip appearance, we clear the existing one
if (tooltipTimeout) clearTimeout(tooltipTimeout);
// Schedule the tooltip to appear at this cursor position after a delay
tooltipTimeout = setTimeout(() => {
update((state) => {
if (state.element) {
state.visible = true;
state.position = { x: e.clientX, y: e.clientY };
}
return state;
});
}, SHOW_TOOLTIP_DELAY_MS);
});
document.addEventListener("mousedown", closeTooltip);
document.addEventListener("keydown", closeTooltip);
// Stop showing a tooltip if the user clicks or presses a key, and require the user to first move out of the element before it can re-appear
function closeTooltip() {
update((state) => {
state.visible = false;
state.element = undefined;
return state;
});
}
return {
subscribe,
};
}
export type TooltipState = ReturnType<typeof createTooltipState>;