fix(web-ui): menu placement and scrolling, tool-row and settings polish

Menus: keep 12px viewport clearance with internal scroll, pin workspace
create actions in a footer, and pre-render portal lists hidden so the
first painted frame is already at its final position (no open jump).
Tool rows: 14px icons, secondary titles, no hover fill, and a hover
chevron preview on in-place expandable rows. Settings: 800x600 layer-2
panel over a blurred mask, hover states, and wrapping selector cubes;
ModelSelect surface tokens now match the Menu primitive.
This commit is contained in:
Yif
2026-07-28 04:25:18 +08:00
parent fed1b23eac
commit 1f79b78045
29 changed files with 367 additions and 175 deletions
@@ -81,23 +81,20 @@ describe('Tooltip', () => {
expect(screen.getByRole('tooltip')).toBeTruthy()
})
it('keeps the bubble while either hover or focus is still active', () => {
it('mouse leave hides the bubble immediately, even while the anchor stays focused', () => {
render(
<Tooltip label="Sticky">
<button type="button">anchor</button>
</Tooltip>,
)
const anchor = screen.getByText('anchor')
// Focused AND hovered: leaving with the mouse must not drop the bubble.
// Focused AND hovered: leaving with the mouse drops the bubble at once.
fireEvent.focus(anchor)
fireEvent.mouseEnter(anchor)
fireEvent.mouseLeave(anchor)
expect(screen.getByRole('tooltip')).toBeTruthy()
fireEvent.blur(anchor)
expect(screen.queryByRole('tooltip')).toBeNull()
// Symmetric: blurring while still hovered keeps it, mouseleave ends it.
// Re-entering shows it again; blurring while still hovered keeps it.
fireEvent.mouseEnter(anchor)
fireEvent.focus(anchor)
fireEvent.blur(anchor)
expect(screen.getByRole('tooltip')).toBeTruthy()
fireEvent.mouseLeave(anchor)