feat(avatar): add Avatar compound atom (size × shape, AvatarGroup) — D14#77
Merged
Conversation
Compound `Avatar` + `AvatarImage` + `AvatarFallback` + `AvatarGroup`
following the shadcn / Radix / Base UI contract. State-of-the-art
validation: 8/10 top-tier DS ship Avatar as a dedicated atom; the
two that do not (Material 3, Carbon core) delegate to their
implementer library which does. Cardinal-rule bar (6/8) cleared.
API highlights:
- 3 named sizes (sm/md/lg = 32/40/48 px) aligned to the IconButton
grid + numeric `size={number}` escape for one-off cases
(108 px profile picture, 20 px compact stack).
- 2 shapes: circle (default) for people, square (radius-md) for
orgs / products.
- Explicit fallback composition (Escuela 1, D11) — no magic `name`
prop, no built-in initials computation.
- AvatarGroup with `max` overflow ("+N" terminal avatar) and
`--pharos-avatar-group-ring` overrideable via CSS var.
- `render` prop on the root for link composition.
- No status badge primitive in v1 — composition with future Badge
positioning when needed.
22 new tests (136 total green). NAMING-decisions.md documents D14
in full with Alexandria mapping (AvatarList, PeopleList, PersonView,
UserAvatar, ProfileSummary, assessment tables, team / access pages).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Tip All tests passed and all changes approved!🟢 UI Tests: 9 visual and accessibility changes accepted as baselines |
Bug: with the root in `display: inline-flex`, `<AvatarImage>` and `<AvatarFallback>` rendered as flex siblings during the load window. Both carry `width: 100%`, so the browser shrank them to 50/50 inside the avatar — visible as a fractured chrome at size=lg and on any docs page rendering multiple Avatars before the browsers decoded the pictures (the deployed Storybook docs route showed this; the Chromatic snapshots looked fine because they wait for image decode before snapping). Fix: lift the image out of the flex flow with `position: absolute` and anchor it via `position: relative` on the root. The fallback stays as the single flex item that centres its content; the image fades in on top once the pixels arrive. Same layering pattern Radix Primitives and Base UI Avatar document. 136 tests still green; no API change, only CSS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Overview gallery (`Pharos/Overview` story) is the single page
where humans eyeball every published component side by side, and
the single Chromatic snapshot that catches cross-component
regressions. Each new Phase 2 atom adds a Showcase entry per the
master plan's 2.X.3 checklist; Avatar joins the Primitives section.
Showcase content covers the three composition paths the atom
documents: image + initials fallback (default circle person),
icon fallback inside a square shape (org / product), initials-only
fallback (no source), and an AvatarGroup with `max={3}` overflow.
Note: Textarea, Spinner, and IconButton remain absent from the
gallery — that drift predates this PR and is logged for a
follow-up. Adding Avatar restores the cadence for everything
shipped from Card onward.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Phase 2 atoms that landed between Card and Avatar
(`Textarea`, `Spinner`, `IconButton`) never made it into the
`Pharos/Overview` gallery — drift that broke the master plan's
2.X.3 rule ("each new atom adds a Showcase entry"). The previous
commit added Avatar; this one closes the gap retroactively so
the gallery again lists every published primitive side by side
and the cross-component Chromatic snapshot covers them.
Showcase contracts mirror the existing patterns:
- Textarea: 4 states (default / readonly / invalid / disabled),
parallel to InputShowcase.
- Spinner: 3 sizes (sm / md / lg), the only axis the atom exposes.
- IconButton: 4 intents + a loading example.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the ninth Pharos atom: a compound
Avatar+AvatarImage+AvatarFallback+AvatarGroupfollowing the shadcn / Radix / Base UI contract. Decision D14 documented in full inNAMING-decisions.md.State-of-the-art validation ahead of the decision: 8/10 top-tier DS ship Avatar as a dedicated atom (shadcn, Radix Primitives, Base UI, MUI, Chakra, Mantine, Ant Design, Polaris). The two that do not in core (Material 3, Carbon) delegate to their implementer library. Cardinal-rule bar (6/8) cleared with margin.
API highlights
sm/md/lg= 32 / 40 / 48 px) aligned to the IconButton height grid.size={number}for one-off cases outside the canonical grid (108 px profile picture, 20 px compact stack — directly motivated by the Alexandria audit).circle(default, person-shaped) andsquare(radius-md, for orgs / products).nameprop, no built-in initials computation. Consumer puts text / icon / image inside<AvatarFallback>.AvatarList/PeopleListalready render avatar stacks):maxcaps visible avatars with a+Noverflow terminal,size/shapecascade to children, ring renders asbox-shadowvia--pharos-avatar-group-ring(defaults to base-white, override-able for tinted surfaces).renderprop on the root composes the Avatar as a different element (<Avatar render={<a href="..." />} />).What v1 leaves out (deliberate)
name → initialsderivation — composition stays explicit.Quality
pnpm typecheck,pnpm lint,pnpm format:check,pnpm build,pnpm verify:dist-typesall green..changeset/avatar-atom.md) — minor bump →0.11.0.main(post Dependabot batch).Storybook
New stories:
Components/Avatar→ Playground, Default, Sizes (3 named + 108 numeric), Shapes (circle / square), Fallbacks (initials / icon / image-error → initials), Group (3-avatar + 5-avatar with max=3), RenderAsLink, Matrix (sizes × shapes).Alexandria mapping (preview, no adoption PR yet)
Documented in
NAMING-decisions.md § Avatar:AvatarList(20 px overlap) →<AvatarGroup size={20} max={N}>PeopleList(32 px overlap) →<AvatarGroup size="sm" max={N}>UserMenu,MobileHeader,RevieweeTable,ForkedAssessmentCard,ModifyRevieweeRow,TeamMembers→<Avatar size="md">ProfileSummary,UserProfileBox→<Avatar size={108}>(numeric escape)request-accessorg logo →<Avatar size={100} shape="square">Adoption PR opens in
alexandria-web-applicationonce this releases on npm and the CTO greenlights (pausa Alexandria respected).Test plan
+N.data-pharos-*attrs from Storybook DOM (size / shape / loading status all stable).🤖 Generated with Claude Code