Let a rich tooltip linger after the focus leaves too

Plan step 36. The rewrite moved the rich tooltip's pointer-leave grace
from 200ms to M3's 1.5s — kept: the reference gives plain and rich
tooltips the same 1.5s, and ACT-25 names this file's 200ms. Its header
claimed the same for the focus, which still hid the bubble at once; the
focus now leaves on the same 1.5s the plain tooltip uses, and the skill
says so. The stylesheet header no longer cites chip.css and fab-menu.css
for a pulled-back actions row neither has.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 17:09:33 +02:00
co-authored by Claude Opus 5
parent 32313e0fd9
commit 97ba035b68
3 changed files with 10 additions and 10 deletions
@@ -449,7 +449,7 @@ A few lines of context around a trigger, with an optional `title` and `actions`
</x-rich-tooltip> </x-rich-tooltip>
``` ```
Shows on hover and keyboard focus; `persistent` opens it on press and keeps it until a press elsewhere or Escape (use it when there are actions). The trigger is pointed at the bubble with `aria-describedby`, so its words are read out with the control. An open bubble stays open while the Livewire component around it renders, its actions' `wire:click` included. `side`: `bottom` (default), `top`, `left`, `right`. Shows on hover and keyboard focus and goes 1.5s after the pointer or the focus leaves, as M3 times a plain tooltip too; `persistent` opens it on press and keeps it until a press elsewhere or Escape (use it when there are actions). The trigger is pointed at the bubble with `aria-describedby`, so its words are read out with the control. An open bubble stays open while the Livewire component around it renders, its actions' `wire:click` included. `side`: `bottom` (default), `top`, `left`, `right`.
### `<x-stat>` ### `<x-stat>`
+2 -3
View File
@@ -5,9 +5,8 @@
* RichTooltipTokens (androidx Compose Material 3, Apache-2.0): surface-container, the medium * RichTooltipTokens (androidx Compose Material 3, Apache-2.0): surface-container, the medium
* corner, elevation 2, 312px wide at most, 16px either side, 12px above the subhead (or the text * corner, elevation 2, 312px wide at most, 16px either side, 12px above the subhead (or the text
* when there is none) and 8px below it. Title-small subhead and body-medium text in * when there is none) and 8px below it. Title-small subhead and body-medium text in
* on-surface-variant, label-large actions in primary the actions row pulls itself back to the * on-surface-variant, label-large actions in primary the actions row pulls itself back 12px to
* text's edge with a negative margin, the trick every text-button row in this package uses * the text's edge, as the alert's actions row does (alert.css).
* (chip.css, fab-menu.css).
* *
* Placed by CSS anchor positioning on `data-md-side`, corner-to-corner so the 312px bubble has * Placed by CSS anchor positioning on `data-md-side`, corner-to-corner so the 312px bubble has
* room to spread past a narrow trigger; `position-try-fallbacks` flips it when the window has no * room to spread past a narrow trigger; `position-try-fallbacks` flips it when the window has no
+7 -6
View File
@@ -1,11 +1,12 @@
/** /**
* `materialRichTooltip`: shows an `<x-rich-tooltip>`. * `materialRichTooltip`: shows an `<x-rich-tooltip>`.
* *
* Transient (the default): like a plain tooltip after a short hover on a pointer that can hover, * Transient (the default): like a plain tooltip (tooltip.js) after a short hover on a pointer
* at once on keyboard focus, standing for M3's 1.5s once the pointer or focus leaves (ACT-25) so * that can hover, at once on keyboard focus, and standing for 1.5s once the pointer or the focus
* the words can still be read while it moves on, and it stays while the pointer moves onto the * leaves, which M3 gives plain and rich tooltips alike (docs/reference/m3/
* bubble to reach its actions. Persistent: a press on the trigger opens it as a light-dismiss * components-actions-communication-containment.md § Tooltips, ACT-25). The bubble is inside the
* popover. * wrapper, so moving onto it to reach its actions, by pointer or by Tab, is no leave at all; Escape
* hides it at once. Persistent: a press on the trigger opens it as a light-dismiss popover.
* *
* The trigger is pointed at the bubble with `aria-describedby`, so the explanation the whole * The trigger is pointed at the bubble with `aria-describedby`, so the explanation the whole
* point of a rich tooltip is read out with the control rather than never at all; a persistent * point of a rich tooltip is read out with the control rather than never at all; a persistent
@@ -73,7 +74,7 @@ document.addEventListener('alpine:init', () => {
wrapper.addEventListener('pointerenter', (event) => event.pointerType === 'mouse' && show(HOVER_DELAY_MS)) wrapper.addEventListener('pointerenter', (event) => event.pointerType === 'mouse' && show(HOVER_DELAY_MS))
wrapper.addEventListener('pointerleave', () => hide(LEAVE_GRACE_MS)) wrapper.addEventListener('pointerleave', () => hide(LEAVE_GRACE_MS))
wrapper.addEventListener('focusin', (event) => event.target.matches(':focus-visible') && show(0)) wrapper.addEventListener('focusin', (event) => event.target.matches(':focus-visible') && show(0))
wrapper.addEventListener('focusout', (event) => !wrapper.contains(event.relatedTarget) && hide()) wrapper.addEventListener('focusout', (event) => !wrapper.contains(event.relatedTarget) && hide(LEAVE_GRACE_MS))
document.addEventListener('keydown', (event) => event.key === 'Escape' && hide()) document.addEventListener('keydown', (event) => event.key === 'Escape' && hide())
}, },