feat(a11y/ui): profile header skeleton, accessible metric tooltips, bio clamp, onboarding placeholders (#291/#290/#282/#273)#311
Merged
Chucks1093 merged 1 commit intoMay 28, 2026
Conversation
…lamp, pending-onboarding placeholders Closes accesslayerorg#291, accesslayerorg#290, accesslayerorg#282, accesslayerorg#273. - accesslayerorg#273: New CreatorProfileHeaderSkeleton (in CreatorSkeleton.tsx) renders avatar (size-24 / md:size-32), name (h-9 / md:h-12), and handle (h-6) block placeholders that align with CreatorProfileHeader's populated layout so no layout shift on resolve. role="status" + sr-only label announce the loading state; reduced-motion is respected via the shared skeleton block class. Wired into LandingPage with isLoading. - accesslayerorg#290: New AccessibleInfoTrigger component — a focusable <button> with aria-describedby + aria-expanded + Escape-to-dismiss. Replaces the hover-only pattern that left keyboard users stranded. MiniStatChip now accepts an optional prop; the LandingPage's profile-stat chips (Status / Audience / Access) carry metric explanations. - accesslayerorg#282: CreatorBio gains a maxLines prop (default 3 on card, ignored on profile). Implementation lives in src/utils/lineClamp.utils so the component file stays Fast-Refresh-friendly. Full bio is kept in the title attribute when clamped so screen readers and tooltips read the unclamped text; the profile page is unaffected. - accesslayerorg#291: New PendingOnboardingPlaceholder component for blank profile sections during onboarding (bio / links / stats / overview variants). CreatorBio also gains isOnboardingPending that swaps its empty-bio fallback for the pending copy. Tests (14 new, all passing): - CreatorBio.test.tsx: 11 lineClampClassFor cases (profile, disabled, 1..6, cap), 5 clamp-integration cases, 3 onboarding-pending cases. - AccessibleInfoTrigger.test.tsx: focusable label, focus reveals tooltip with aria-describedby, blur hides, Escape dismisses, click toggles, default label fallback. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@pre-cious-Igwealor Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Chucks1093
pushed a commit
that referenced
this pull request
May 28, 2026
…with drag-to-dismiss Closes #315, #314. - #315 CreatorBio: gains collapsible + collapsedMaxLines + collapseThresholdChars props. When enabled on the profile variant and the bio is long enough (default >200 chars), the paragraph renders clamped with a focusable Show more / Show less toggle that carries aria-expanded + aria-controls so screen readers know the bio's collapsed state. Short bios are unaffected (no toggle, no clamp). The card variant ignores collapsible since it already clamps via maxLines. Wired into CreatorProfileHeader where the profile bio actually renders. - #314 BottomSheet: new mobile-first primitive built on Radix Dialog for the focus trap / role / Escape handling. Adds drag-to-dismiss via native pointer events: * The visual handle (BottomSheetHandle) registers itself with the sheet's content surface so a gesture that starts on the handle is always treated as 'grabbing the sheet'. * Otherwise the gesture is captured only when no inner scroller is engaged (walks up from the target, bails if any ancestor has scrollTop>0) — so a downward swipe on scrollable content scrolls instead of dismissing. * Dragging past dismissThresholdPx (default 96) dismisses by dispatching Escape so Radix's onOpenChange(false) pipeline runs. * Short / upward drags snap back via a brief transform reset. * The default close button always works as an alternative; pass enableDrag=false to make it the only path. Tests (12 new, all passing): - src/components/common/__tests__/CreatorBio.test.tsx (6 new cases): no toggle for short bio, no engagement on card variant, clamps + Show more wiring, toggles to Show less + removes clamp, custom collapseThresholdChars, custom collapsedMaxLines. - src/components/ui/bottom-sheet.test.tsx (6 cases): render + handle + close button, close-button dismissal, drag past threshold dismisses, short drag does not, upward drag clamps + never dismisses, enableDrag=false leaves close button as only path. Repo verification: - pnpm test 129/130 (1 pre-existing CreatorInitialsAvatar failure, same one disclosed in #310 / #311 / #324). - pnpm lint clean - pnpm build clean Co-Authored-By: Claude Opus 4.7 <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.
This PR closes #291, #290, #282, #273 — all four are creator-profile presentation/accessibility issues in adjacent components, so one PR keeps the diff coherent.
closes #291
closes #290
closes #282
closes #273
What's in this PR
#273 — Loading skeleton for the creator profile header
CreatorProfileHeaderSkeleton(exported alongsideCreatorSkeletoninsrc/components/common/CreatorSkeleton.tsx).CreatorProfileHeader's populated layout exactly: avatarsize-24 md:size-32 rounded-2xl border-4, nameh-9 md:h-12 w-3/4 max-w-md, handleh-6 w-1/2 max-w-xs, and ahidden md:blockshare-button block — so no visible layout shift when real data resolves.role="status"+sr-onlylabel announces "Loading creator profile" to assistive tech.skeletonBlockClass(which already doesmotion-reduce:);disableShimmeris forwarded for callers that disable shimmer higher up the tree.LandingPage— whenisLoadingis true, the header section renders the skeleton instead of the populatedCreatorProfileHeader.#290 — Accessible tooltip trigger for creator metric explanations
The existing
Tooltipwraps content in a non-focusable<div>and toggles viagroup-hover/group-focus-within. That's effectively hover-only — keyboard users can't reach the explanation on a plain label.AccessibleInfoTriggercomponent:<button type="button">with a metric-specificaria-label("Explanation for: Audience"), so it's focusable and announced.role="tooltip"element appears and the trigger getsaria-describedby={tooltipId}+aria-expanded={true}.MiniStatChipaccepts an optionalexplanationprop and renders the trigger when supplied.#282 — Helper for truncating long creator bio text to max display lines
CreatorBiogains amaxLines?: number | nullprop. Default 3 on thecardvariant; theprofilevariant always shows the full bio so the truncation stays purely cosmetic and the full text remains accessible on the creator profile page. Short bios are unaffected.maxLines1..6 to a fixed Tailwindline-clamp-Nclass (capping higher values atline-clamp-6to keep card heights bounded). Fixed class names are used so Tailwind's JIT keeps the utilities in the produced CSS.titleattribute when clamped, so accessibility tooling and browser tooltips can read the unclamped text.src/utils/lineClamp.utils.tsrather than in the component file so the component keeps a clean Fast-Refresh boundary (one component per file).#291 — Placeholder copy for creator profile with pending onboarding
PendingOnboardingPlaceholdercomponent withinlineandcardvariants andbio/links/stats/overviewsection presets. Centralising the copy keeps tone consistent across every empty-state surface — change once, propagates everywhere.CreatorBioacceptsisOnboardingPending. When true and the bio is empty, the fallback swaps to the pending copy ("This creator is still setting up their profile. Bio coming soon.") and thearia-labelflips to "Bio pending — onboarding in progress" so screen readers communicate the cause of the empty state.Verification
14 new vitest cases, all passing:
CreatorBio.test.tsx(added): 11lineClampClassForcases (profile, disabled, 1..6, cap), 5 clamp-integration cases (default 3-line, override, null disables, profile ignores, title preserves full text), 3 onboarding-pending cases (fallback swap, default branch, ignored when bio present).AccessibleInfoTrigger.test.tsx(new): focusable label, focus reveals tooltip + aria-describedby + aria-expanded, blur hides, Escape dismisses, click toggles back off, default-label fallback.Disclosures (pre-existing on
main, unrelated to this PR)src/components/common/__tests__/CreatorInitialsAvatar.test.tsxfails onmain. The test callsgetByLabelText('Alex Rivers initials avatar')but the component renders the initials witharia-hidden="true"(no matchingaria-label). Reproducible on unmodified upstreammain; the failing component / test were modified independently of this PR (commitse92b472/0213bcd). Not touched here.PendingOnboardingPlaceholderships as a new component but is only consumed throughCreatorBio'sisOnboardingPendingflag in this PR. Wiring it intoCreatorProfileInfoGridand the social links list would require those components to know about onboarding state, which they currently don't — that surface area is a logical follow-up, not part of the four issues' scope.