You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/audit/components/tooltip.md

4.8 KiB

Audit: tooltip

audit-version: 1 audited-at: 2026-06-26 scope: ['soma', 'eidos', 'sema'] method: adversarially-verified workflow (analyze → refute); HIGH/CRITICAL personally re-verified against cited code by the lead. provider: src/uix/soma/components/tooltip/tooltip-provider.svelte.ts

Summary

Counts (post-verification): CRITICAL 0 · HIGH 0 · MEDIUM 1 · LOW 1. systemic hits: SYS-6.

Findings

MEDIUM: Test Coverage — Keyboard/Dismissal — tooltip-003

  • dimension: F
  • rule: Test Coverage — Keyboard/Dismissal
  • location: src/uix/soma/components/tooltip/tooltip-provider.svelte.test.ts:1-322
  • evidence: Test env is @vitest-environment jsdom (line 1). 4 test cases (describe lines 116-322) cover: timer delay/close/skip-delay, focus/blur/disabled state, click/Enter/Space on trigger, parts registration/linking. MISSING: Escape key close, dismissal flow, content pointer enter (which cancels close).
  • impact: Keyboard routes (Enter/Space) and Escape dismissal behavior are not verified. jsdom-only environment cannot catch DOM interaction edge cases. High-risk behavior untested on the difficult path (keyboard/escape).
  • proposed-fix: Add test case for onkeydown with Escape key triggering handleClose via Dismissal layer. Add test for content onpointerenter calling cancelClose(). Consider promoting at least the Escape path to a client/Playwright test to verify in real browser.
  • verify: [confirmed] Confirmed. Test env is jsdom (test file line 1 // @vitest-environment jsdom). The 4 it blocks (lines 122,178,218,265) cover: delay/close/skip-delay timers, focus/blur/disabled, click + Enter/Space close (lines 241-259), parts registration/aria-describedby/role linking. There is NO test exercising (a) the Escape -> Dismissal.onEscapeKeydown -> handleClose path (provider lines 456-465) or (b) content onpointerenter -> cancelClose() (provider lines 482-486), which is the hoverable-tooltip cancel-close behavior. Both are real provider behaviors on a moderate-risk path left unexercised. MEDIUM is appropriate; matches SYS-3 (interaction-heavy + jsdom-only + dismissal/cancel paths untested).
  • fix-status: open

LOW: E-bis MAGIC NUMBERS — tooltip-002

  • dimension: E-bis
  • rule: E-bis MAGIC NUMBERS
  • location: src/uix/eidos/components/tooltip/tooltip.css:86
  • evidence: stroke-width: 1px; in outline variant arrow selector. Recipe base.ts declares tooltip.'border-width': 'var(--border-width)' (line ~1), but CSS uses literal 1px instead of that token.
  • impact: Design token inconsistency. Outline variant arrow stroke width is hardcoded; if border-width is ever updated at the design system level, outline arrow won't scale with it. Token discipline breach.
  • proposed-fix: Replace 'stroke-width: 1px;' with 'stroke-width: var(--tooltip-border-width);' or confirm 1px is intentionally different from the canonical border-width scale (unlikely).
  • verify: [downgraded] Confirmed the literal exists but downgraded MEDIUM->LOW. tooltip.css:86 reads stroke-width: 1px; in the outline-variant arrow rule. The recipe DOES declare base.ts:3908 'border-width': 'var(--border-width)', and the box border at tooltip.css:31 uses border: var(--tooltip-border-width) solid .... So the 1px on the SVG arrow stroke is a real but trivial token-discipline nit on a 1px hairline that conceptually mirrors the box border (--border-width itself resolves to 1px). No user-visible, behavioral, or theming consequence — token hygiene only. LOW, not MEDIUM.
  • fix-status: open

No-findings dimensions

A, B, C, D

Theming facts (E-bis)

  • magic z-index: none
  • magic literals: stroke-width: 1px (line 86, should use --tooltip-border-width)
  • undeclared parts: data-size (content part) | data-variant (content part)
  • roles clean: true · variants clean: true

Tests (F)

  • exists: true · env: jsdom
  • covers: timer-based open/close delay; group skip-delay coordination; focus/blur instant open/close; disabled state respect; click/Enter/Space trigger close; part registration and id linking; aria-describedby linking
  • untested: Escape key dismissal; Content pointer enter (cancelClose); Dismissal onEscapeKeydown flow

Style observations (non-blocking)

  • Morfo contract is clean and well-structured; trigger + content both use correct 'instant-open' state derivation
  • A30 id registration pattern is correct (constructor-time assignment via opts.id)
  • SafePolygon integration for hoverable content is properly configured with transitIntentTimeout
  • Timer disposal in $effect root is correct
  • Two-moments sequence 'pre' is correct for all three events (open/close/close-dismiss)
  • Eidos recipe properly declares all component tokens including content-z, padding variants, and font-size scale
  • Keyboard handling on trigger (Enter/Space to close when open) matches the pattern from baseline dropdown-menu

Powered by TurnKey Linux.