Skip to content

Add Popover component - #551

Open
titouanmathis wants to merge 1 commit into
mainfrom
feat/popover-component
Open

Add Popover component#551
titouanmathis wants to merge 1 commit into
mainfrom
feat/popover-component

Conversation

@titouanmathis

Copy link
Copy Markdown
Contributor

What

A new headless Popover primitive — the non-modal sibling of Dialog, wrapping the native Popover API.

It offloads top-layer stacking, Esc and (with popover="auto") light-dismiss to the platform, and only orchestrates transitions — fanning enter()/leave() out to every Transition / ViewTransition child, exactly like Dialog.

Design

  • Triggers via Action, no custom attributes. The component exposes open() / close() / toggle(); the HTML wires them: data-on:click="Popover(#menu)->target.toggle()" for a dropdown, data-on:mouseenter/data-on:mouseleave/data-on:focus/data-on:blur for a tooltip, data-on:keydown="event.key === 'Escape' && Popover.close()" for Esc.
  • auto vs manual is the author's choice. manual (used in the examples) lets the component own show/hide so the leave transition always plays, with dismissal re-added via Action; auto trades that for free platform light-dismiss (an instant close), with the native toggle event kept in sync so the close event still fires.
  • No positioning opinion. Neutralize the UA overlay styles and place it yourself — the examples use native CSS anchor positioning.

API

Properties popover (the [popover] element), transitions
Methods open(), close(), toggle() — all Promise<void>
Events open, close

What's included

  • packages/ui/Popover/ — component + barrel export, added to the main @studiometa/ui export.
  • packages/tests/Popover/Popover.spec.ts — 10 tests (open/close/toggle, no-ops, event emission, fanning transitions out, leave-before-hide ordering, and platform light-dismiss sync). Exports snapshot updated.
  • packages/docs/components/Popover/ — overview, JS API, and two example stories (dropdown menu + tooltip).

Verification

  • npm run lint — 0 errors, types pass. npm run test — 491 passed. npm run docs:build — succeeds.
  • The exact example markup (Action-wired triggers, manual popover, Transition child, anchor positioning) was validated in a browser (Playwright/Chromium): clean click-toggle with no light-dismiss reopen race, Esc + item-click dismissal, and hover/focus tooltip open/close.

Follow-up

Once this lands, Combobox/Listbox builds directly on top of Popover.

🤖 Generated with Claude Code

A headless wrapper around the native Popover API — the non-modal sibling
of Dialog. The `[popover]` element gives top-layer stacking, Esc and
(with `popover="auto"`) light-dismiss for free; the component only
orchestrates transitions, fanning enter()/leave() out to every
Transition/ViewTransition child.

It ships no markup and no triggers: opening and closing are wired from
HTML with Action (`Popover(#id)->target.toggle()` for a dropdown,
mouseenter/mouseleave for a tooltip), and positioning is left entirely to
author CSS. `auto` vs `manual` is the author's choice — `manual` keeps the
leave transition (dismissal re-added via Action), `auto` trades it for
free platform light-dismiss, with the native `toggle` event kept in sync.

Adds the component + barrel export, unit tests, and docs (overview, JS
API, and dropdown + tooltip example stories).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.42857% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.91%. Comparing base (db20454) to head (27e3381).

Files with missing lines Patch % Lines
packages/ui/Popover/Popover.ts 91.42% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #551      +/-   ##
============================================
+ Coverage     84.84%   84.91%   +0.06%     
  Complexity      145      145              
============================================
  Files           112      113       +1     
  Lines          3610     3645      +35     
  Branches        679      685       +6     
============================================
+ Hits           3063     3095      +32     
- Misses          477      479       +2     
- Partials         70       71       +1     
Flag Coverage Δ
unittests 84.91% <91.42%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/ui/Popover/Popover.ts 91.42% <91.42%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown

Export Size

@studiometa/ui

Name Size Diff
Popover 2.06 kB +2.06 kB (+100.00%) 🔺
Unchanged

@studiometa/ui

Name Size Diff
AbstractFrameTrigger 1.74 kB -
AbstractPrefetch 366 B -
AbstractScrollAnimation 3.87 kB -
AbstractSliderChild 702 B -
Accordion 1.78 kB -
AccordionItem 1.66 kB -
Action 1.11 kB -
AnchorNav 3.88 kB -
AnchorNavLink 3.77 kB -
AnchorNavTarget 125 B -
AnchorScrollTo 2.56 kB -
animationScrollWithEase 763 B -
CircularMarquee 506 B -
Cursor 650 B -
DataBind 3.64 kB -
DataComputed 3.72 kB -
DataEffect 3.7 kB -
DataModel 3.75 kB -
DataScope 1.35 kB -
Dialog 2.43 kB -
Draggable 1.61 kB -
Fetch 2.37 kB -
FetchShopifyPartial 2.81 kB -
Figure 1.81 kB -
FigureShopify 2.08 kB -
FigureTwicpics 2.34 kB -
FigureVideo 1.98 kB -
FigureVideoTwicpics 2.56 kB -
Frame 3.47 kB -
FrameAnchor 1.84 kB -
FrameForm 1.92 kB -
FrameLoader 1.45 kB -
FrameTarget 1.75 kB -
FrameTriggerLoader 1.46 kB -
Hoverable 904 B -
Indexable 1.02 kB -
InView 157 B -
InViewOnce 206 B -
LargeText 678 B -
LazyInclude 322 B -
Menu 2.33 kB -
MenuBtn 140 B -
MenuList 1.9 kB -
Modal 2.11 kB -
ModalWithTransition 2.22 kB -
Panel 2.51 kB -
PrefetchWhenOver 408 B -
PrefetchWhenVisible 417 B -
ScrollAnimation 4 kB -
ScrollAnimationChild 4.12 kB -
ScrollAnimationChildWithEase 4.72 kB -
ScrollAnimationParent 4.18 kB -
ScrollAnimationTarget 4.06 kB -
ScrollAnimationTimeline 4.12 kB -
ScrollAnimationWithEase 4.6 kB -
ScrollReveal 1.63 kB -
Sentinel 129 B -
Slider 3.65 kB -
SliderBtn 928 B -
SliderCount 753 B -
SliderDots 1.97 kB -
SliderDrag 269 B -
SliderItem 958 B -
SliderProgress 1.06 kB -
Sticky 771 B -
Tabs 1.38 kB -
Target 86 B -
Timer 496 B -
TimerProgress 627 B -
Track 1.64 kB -
TrackContext 340 B -
TrackShopify 1.72 kB -
Transition 1.41 kB -
viewTransition 295 B -
ViewTransition 738 B -
withDeprecation 199 B -
withIndex 968 B -
withScrollAnimationDebug 2.03 kB -
withTransition 1.39 kB -

@github-actions

Copy link
Copy Markdown

Code Review

Risk: Low — no blocking issues; safe to merge aside from nits.

Adds a new headless Popover primitive to @studiometa/ui, exports it from the main package barrel, and documents it with overview/API pages plus dropdown and tooltip stories. The implementation mirrors Dialog by orchestrating Transition / ViewTransition children and syncing open / close events with native popover toggle events. Tests cover the basic lifecycle, transition fan-out, ordering, and platform light-dismiss synchronization.


Review usage: 265,452 in (214,016 cached) / 10,300 out tokens — $0.3366 (cloudflare-ai-gateway/gpt-5.4, thinking: medium)

Reviewed by @weareikko/code-review v0.9.3 for commit 27e3381.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant