Skip to content

Align avatar to architecture goals#196

Merged
lifeiscontent merged 4 commits into
mainfrom
align/avatar
Jun 24, 2026
Merged

Align avatar to architecture goals#196
lifeiscontent merged 4 commits into
mainfrom
align/avatar

Conversation

@lifeiscontent

Copy link
Copy Markdown
Collaborator

Closes #118

Designer spec recap

From bhaveshraja's comment on #118:

  • Always the same: circular shape (user) / rounded-square (workspace), content priority order image→initials→icon, equal width+height, max-2-char uppercased initials, deterministic fill color, border width scaling with magnitude, no intrinsic hover/animation, presentational by default, consistent group overlap.
  • Depends (adjustable): magnitude (8 steps), variant (image/initials/icon resolved by content), content (src/name), interactive vs presentational (wrapper's concern), color mode (semantic tokens handle automatically).

The component already correctly models the "always the same" items as baked-in behavior (shape via rounded-full, border scaling in avatarVariants, content priority via Base UI's Avatar.Root + AvatarFallback fallback logic). This PR tightens the architecture on the remaining class-map violation.

Architecture changes

iconSizeByMagnitude Record → avatarIconVariants cva (ui/avatar/variants.ts):
The components/avatar had a raw Record<AvatarMagnitude, string> for icon sizes. Per the architecture rule that all className composition lives in cva variants (never as Records in component files), this is now avatarIconVariants — a proper cva exported from variants.ts. The components/avatar imports and calls it instead of a raw lookup.

initialsToneClass Record → avatarToneBgClass in variants.ts:
The tone→background-class map was defined inline in ui/avatar/avatar.tsx. Since variants.ts is the single source of truth for className decisions, the map now lives there as avatarToneBgClass. The existing initialsToneClass export in avatar.tsx is preserved (so workspace-avatar keeps working) but now delegates to that source, eliminating the duplicate definition.

No visual or behavioral changes. All existing stories and the CSS check play test remain intact. vp check --fix passes clean on all avatar files.


Needs design approval from bhaveshraja before merge.

@github-actions

Copy link
Copy Markdown

📚 Storybook preview: https://pr-196-propel-storybook.vamsi-906.workers.dev

Move className lookup maps out of component files and into variants.ts:
- avatarIconVariants (cva): replaces the iconSizeByMagnitude Record in
  components/avatar; icon size is now driven through the variants system
- avatarToneBgClass: consolidates the duplicate inline tone→bg map into
  variants.ts; the avatar.tsx re-export of initialsToneClass now delegates
  to that single source of truth

Closes #118
The anonymous person-icon was rendered directly in the components-tier Avatar,
which reached into ui/avatar/variants for avatarIconVariants and applied it as a
className on a lucide User glyph. That put styling in the components tier and left
the avatar fallback baking in its own icon child.

Add an AvatarIcon ui part: a node-slot that sizes its single child to the
magnitude's icon size via --node-size (Figma's explicit per-step icon px), tinted
muted, and defaulting to a person glyph. The components-tier Avatar now composes
<AvatarFallback><AvatarIcon /></AvatarFallback> with no className, and the ui story
composes AvatarIcon for the anonymous state and registers it in subcomponents.
AvatarIcon baked a default person glyph via children ?? <User />. A ui part
must render only its single child and bake no glyph. Move the default into the
components-tier Avatar composition (passes <User /> as the AvatarIcon child) and
have the ui story pass it explicitly too. Same glyph and size, just relocated.
@lifeiscontent lifeiscontent merged commit db66f29 into main Jun 24, 2026
2 checks passed
@lifeiscontent lifeiscontent deleted the align/avatar branch June 24, 2026 10:42
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.

Avatar: what should always look the same, and what should be adjustable?

1 participant