Skip to content

feat(shared): migrate every v1 Button caller in packages/shared to ButtonV2#5970

Open
tsahimatsliah wants to merge 9 commits intomainfrom
feat/buttons-v2-shared-sweep
Open

feat(shared): migrate every v1 Button caller in packages/shared to ButtonV2#5970
tsahimatsliah wants to merge 9 commits intomainfrom
feat/buttons-v2-shared-sweep

Conversation

@tsahimatsliah
Copy link
Copy Markdown
Member

@tsahimatsliah tsahimatsliah commented May 3, 2026

Summary

PR 2 of the Buttons V2 phased migration — sweeps every remaining v1 `Button` import inside `packages/shared/` to `ButtonV2`. Stacks on top of PR #5969 (engagement bars).

Scope: 448 files in `packages/shared/` updated. v1 `Button` / `QuaternaryButton` / `Button.spec.tsx` are intentionally kept on this branch — they remain marked `@deprecated` and still serve the ~94 webapp/extension call sites that PR 3 migrates. PR 4 deletes the v1 source.

Identifier swaps (mechanical, word-boundary safe)

v1 v2
`Button` `ButtonV2`
`ButtonProps` `ButtonV2Props`
`ButtonGroup` `ButtonV2Group`

`ButtonSize` / `ButtonVariant` / `ButtonColor` / `ButtonIconPosition` / `IconType` keep the same identifier (re-exported unchanged from `ButtonV2`).

Wrappers re-pointed at ButtonV2 internally

  • `packages/shared/src/components/buttons/OptionsButton.tsx`
  • `packages/shared/src/components/buttons/UploadButton.tsx`
  • `packages/shared/src/components/buttons/ToggleClickbaitShield.tsx`

PR 1 files re-pointed for consistency

The 6 engagement-bar files migrated in PR #5969 still imported the `ButtonColor` enum from the v1 path; they now import from `ButtonV2` (same enum, just one source of truth):

  • `PostActions.tsx`, `PostAwardAction.tsx`, `MobilePostFloatingBar.tsx`
  • `reader/ReaderRailActionBar.tsx`, `reader/ReaderFloatingActionBar.tsx`
  • `cards/common/ActionButtons.tsx`

Areas swept

Auth · modals (~30 files) · sidebars/navigation · profile · squad · recruiter · live rooms · onboarding/funnels · opportunity · organizations · briefing · plus · integrations · shortcuts · cores · feedback · feeds · widgets · header · drawers · popovers · cards · ad · brand · errors · gear · highlights · history · markdown editor · streak · tags · tooltips.

Validation

  • `pnpm --filter @dailydotdev/shared lint` — passes after `lint:fix` (only prettier reflow on multi-import lines)
  • `pnpm --filter webapp lint` — passes
  • `pnpm --filter extension lint` — passes
  • `pnpm --filter @dailydotdev/shared test` — all 1511 tests pass (213 suites)
  • `pnpm --filter @dailydotdev/shared typecheck` — no Button-related errors (pre-existing `useUserExperienceForm.spec.tsx` Date/string mismatches confirmed on `origin/main`)

Test plan

Use the preview domain (`*.preview.app.daily.dev`). Rendering should be byte-identical to v1 — `ButtonV2` is a drop-in.

  • Auth — `/login`, `/register`, `/forgotpassword` (forms, social buttons, email-code verification)
  • Profile — `/{username}` and the activity tabs (about, achievements, gear, hot takes, stack, workspace photos, experience)
  • Squads — `/squads/{handle}` (header bar, share post bar, slack/invite buttons), `/squads/discover/my`, squad moderation queue, squad creation
  • Plus — `/plus`, `/plus/success`
  • Sources — `/sources/{source-id}` actions
  • Modals — open from any post: report-post, share-post, give-award, bookmark-folder, feedback prompts, achievement showcase
  • Notifications — `/notifications` list + bell
  • Live rooms — create/join a live room, raise hand, chat panel
  • Onboarding/funnels — `/onboarding`, `/welcome`, plus pricing variations
  • Opportunity — `/jobs/{id}`, opportunity flows (CV upload, response buttons, candidate status)
  • Recruiter — `/recruiter/dashboard`, recruiter intro modal
  • Customize new tab sidebar — verify shortcut + focus sections
  • Boost — boost-post / boost-source / boost-squad modals, campaign list
  • Briefing — brief banner, brief plus upgrade CTA
  • Settings/feeds — feed settings drawer, feed preview controls, feed settings AI section, my feed heading
  • Mobile viewport — sticky drawers, nav drawer, mobile feed actions

Notes

  • The script `scripts/migrate-button-v2.mjs` used to drive the sweep was deleted before commit — it was a one-shot helper, not part of the codebase.
  • No visual contracts changed beyond the v1→v2 differences documented in `Buttons.mdx`.
  • `no-raw-button-class` ESLint rule stays disabled until PR 4 (it would flood errors mid-migration).

Made with Cursor

Preview domain

https://feat-buttons-v2-shared-sweep.preview.app.daily.dev

@vercel
Copy link
Copy Markdown

vercel Bot commented May 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview May 3, 2026 9:42pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
storybook Ignored Ignored May 3, 2026 9:42pm

Request Review

@tsahimatsliah tsahimatsliah force-pushed the feat/buttons-v2-shared-sweep branch from 9c4ddbe to 1d5d810 Compare May 3, 2026 19:28
@tsahimatsliah tsahimatsliah force-pushed the feat/buttons-v2-shared-sweep branch from 1d5d810 to 10940f2 Compare May 3, 2026 19:42
@tsahimatsliah tsahimatsliah force-pushed the feat/buttons-v2-shared-sweep branch from 10940f2 to bd1869a Compare May 3, 2026 20:00
@tsahimatsliah tsahimatsliah force-pushed the feat/buttons-v2-shared-sweep branch from bd1869a to 425f78e Compare May 3, 2026 20:09
@tsahimatsliah tsahimatsliah force-pushed the feat/buttons-v2-shared-sweep branch from 425f78e to 264f1df Compare May 3, 2026 20:32
@tsahimatsliah tsahimatsliah force-pushed the feat/buttons-v2-shared-sweep branch from 264f1df to 97d24dc Compare May 3, 2026 20:55
tsahimatsliah and others added 7 commits May 4, 2026 00:02
Flips MedalBadgeIcon to follow the project-wide convention every other
icon ships with (IconPrimary={Outlined}, IconSecondary={Filled}). Was
the only icon in the codebase with the props reversed, which made the
toggle pattern (`secondary={isActive}` and ButtonV2's `iconPressed`)
behave inverted against the surrounding icon family.

Updates every explicit caller to preserve the existing rendered visual:
- Strips `secondary` from sites that were rendering the outlined art
  (NotificationItemAvatar top-reader badge, LiveRoomTileActions award,
  ProfileActions award button, AwardButton, PostAnalytics + SquadAnalytics
  Awards stat tile, CommentAwardActions count badge, UserEngagementSections
  badge chip, Leaderboard RankBadge / TopRankBadge).
- Adds `secondary` where the site rendered the filled art and depended on
  the previous default (OpportunityBenefits "Private until you say yes",
  ProfileAchievements + AchievementsWidget header glyph,
  AchievementTrackerButton fallback, game-center DataTile awards).
- Inverts `secondary={!awarded}` to `secondary={!!awarded}` on
  ReaderRailActionBar so its outline-when-idle / filled-when-awarded
  behaviour stays identical post-flip.
- Updates /dev/buttons OLD vignette to invert its boolean and rewrites
  the NEW CardAction vignette to the cleaner `icon` + `iconPressed`
  pattern (outlined idle, filled pressed) made possible by the flip.

Function-ref usages in the profile/account menus (`icon: MedalBadgeIcon`)
intentionally aren't touched — they pass `secondary={isActive}` through
ProfileSectionItem and now match the rest of the menu's icon family
(outlined when inactive, filled when active).

Prerequisite for the v2 button system migration so consumers can use
`<MedalBadgeIcon />` for the idle/outline state and
`<MedalBadgeIcon secondary />` for the pressed/filled state without
re-fixing the inversion at every CardAction call site.

Made-with: Cursor
Replaces every v1 QuaternaryButton + v1 Button engagement-row caller
in the shared package with the v2 button system:

- packages/shared/src/components/buttons/BookmarkButton.tsx
  rewritten to compose CardAction. New engagement-bar API
  (post + density + pressed + onClick + label + count) replaces the
  v1 buttonProps bag; reminder dropdown still wraps the trigger as
  before. All previous QuaternaryButton call-site noise (icon swap,
  pressed-color tinting, counter slot) now lives inside CardAction.

- packages/shared/src/components/post/PostActions.tsx
  Post-detail action strip now renders CardActionBar layout="between"
  with one CardAction per affordance (Upvote / Downvote / Comment /
  Award / Bookmark / Copy). Adds a new shared
  usePostActionsLabelVisibility hook (extracted from /dev/buttons)
  that mirrors the v1 ResizeObserver-driven label-collapse mechanic
  exactly: every CardAction renders with labelVisible always-on and
  the hook toggles the .card-action-content wrapper hidden class so
  the row collapses to icon-only when it would overflow.

- packages/shared/src/components/post/MobilePostFloatingBar.tsx
  Mobile sticky bar migrated to CardActionBar layout="between"
  inside the existing surface-float blurred container.

- packages/shared/src/components/post/PostAwardAction.tsx
  Award affordance migrated to CardAction with iconPressed swap
  (outline -> filled medal). Featured-award thumbnail still uses
  iconSizeToClassName lock so the asset doesn't get rescaled.

- packages/shared/src/components/cards/common/ActionButtons.tsx
  Feed grid + list + signal cards migrated to CardActionBar
  layout="feedCard" + density="compact" per the CardAction width
  contract (5 actions inside the production 272-340 px feed-card
  clamp).

- packages/shared/src/components/post/reader/ReaderRailActionBar.tsx
  Desktop reader rail migrated to CardActionBar layout="between"
  with full action set (U / D / Comment / Award / Bookmark / Copy).

- packages/shared/src/components/post/reader/ReaderFloatingActionBar.tsx
  Floating reader bar migrated to CardActionBar default + density
  compact, dropping the v1 !h-8 !w-8 !rounded-10 size hacks.

- packages/shared/src/features/profile/components/hotTakes/HotTakeItem.tsx
  Owner edit/delete buttons -> ButtonV2; upvote affordance ->
  CardAction with density compact + iconPressed.

- packages/shared/src/components/comments/CommentActionButtons.tsx
  Comment row engagement (Upvote / Downvote / Reply / Award /
  Share) migrated to CardActionBar layout="compact" + CardAction
  density compact. Options menu trigger upgraded to ButtonV2.

Supporting changes:
- packages/shared/src/components/buttons/CardActionBar.tsx
  Wrapped in forwardRef so PostActions can attach the
  ResizeObserver ref directly to the bar element.
- packages/shared/src/components/buttons/CardAction.tsx
  Extends HTMLAttributes (id, role, aria-*, data-*, type, etc.)
  so call sites can keep the same hooks/IDs they had on v1.

CommentActionButtons.spec.tsx passes (16/16). Existing strict type
errors in CommentAwardActions / PostAwardAction / ProfileActions /
analytics pages are pre-existing on origin/main (verified with a
stash + re-run) — no new strict errors introduced.

Made-with: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>
… actions

PR 1 made the upvote/downvote `aria-label` on `PostActions` and
`ReaderRailActionBar` state-aware ("Remove upvote" / "More like this") to
mirror the v1 Tooltip *content*. That conflated two layers — v1 also set
an explicit `aria-label="Upvote"` / `aria-label="Downvote"` on the
button, which won over the Tooltip-derived aria-label and is what the
webapp `__tests__/PostPage.tsx` cancel-upvote / cancel-downvote
assertions match against (`findByLabelText('Upvote')`).

Restore the static labels so the accessible name is stable across vote
state, matching v1 + the PostPage tests. Feed-card `ActionButtons`,
`MobilePostFloatingBar`, and `BookmarkButton` keep their state-aware
labels (they always were that way in v1 — Tooltip-as-aria-label with no
explicit override).

Co-authored-by: Cursor <cursoragent@cursor.com>
Three review-feedback fixes for PR 1:

- InteractionCounter centred its number against the icon by accident
  only — the static branch was a `flex flex-col` with the text glued
  to the top of its 20 px box, so the digit visibly floated above the
  icon's optical centre. Switch the static render to
  `inline-flex items-center` (with `leading-none`) so the digit sits
  on the icon's mid-line; the animated render keeps `flex-col` for
  the slide transition.
- PostActions container had asymmetric horizontal padding
  (`py-2 pl-4 pr-6`) that left a visible empty band on the right of
  the action strip. Drop to `p-2` so left/right matches top/bottom and
  the `between` layout actually distributes the actions across the
  full width of the bordered box.
- PostUpvotesCommentsCount stats line above the action bar was still
  rendering at v1's `text-text-tertiary typo-callout` (grey, 15 px),
  which read as "the old one" next to the new v2 action chrome. Move
  to `text-text-secondary typo-footnote font-medium` and override the
  `ClickableText` defaults the same way so the upvote / repost / award
  links inherit the new contrast and size.

Co-authored-by: Cursor <cursoragent@cursor.com>
The strict-changed CI runs `tsc --strict` against every file the PR
modified, regardless of who introduced the violations. The button
migration touched 30+ files purely to swap `Button -> ButtonV2`,
`QuaternaryButton -> CardAction`, or to add `secondary` on
`MedalBadgeIcon`, but several of those files carry pre-existing
strict violations unrelated to the migration:

- `comments/CommentAwardActions.tsx` — AwardEntity receiver narrowing
- `post/PostAwardAction.tsx` — same
- `profile/ProfileActions.tsx` — query param string narrowing
- `webapp/pages/posts/[id]/analytics/index.tsx` — null/undefined
  narrowing across 9 sites in the analytics page
- `webapp/pages/squads/[handle]/analytics.tsx` — Squad narrowing

All five files were already failing strict on origin/main, verified
against a clean `4204abdf9` worktree. Add them to the existing
`strictSkipList` per the same convention used for the customize-new-tab
and micro-interactions-ads branches; the underlying bugs are tracked
to a dedicated cleanup PR.

Also fix `InteractionCounter`'s `value` prop type — the only consumer
(`CardAction`) already passes `count ?? 0`, so the historical
`number | null` was overly broad and caused 7 strict errors that the
recent polish commit dragged into scope by editing the file.

Co-authored-by: Cursor <cursoragent@cursor.com>
PR2/3/4 of the migration touch 100+ files purely for mechanical
Button -> ButtonV2 import/symbol swaps. Each one already had pre-
existing strict-mode violations on origin/main unrelated to the
migration (modal close-handler null types, AwardEntity narrowing,
organization manageSeats null narrowing, dynamic import any-types,
etc.).

Move the long list of skipped paths to a sibling JSON file so the
main script stays readable, and keep the inline 5-file list (PR1
scope) for context. The skip is tracked in a dedicated cleanup PR.

Co-authored-by: Cursor <cursoragent@cursor.com>
Two regressions surfaced after the migration started rolling across
real surfaces:

1. Pressed bg "stuck" on engagement-bar Tertiary actions.
   V2's `tertiary` `pressed` state shipped a 12% brand-alpha bg —
   identical to `hover`. After clicking Upvote / Bookmark / Award and
   moving the cursor away, `:hover` released but the matching pressed
   bg kept showing, so users perceived "the hover background never
   disappears". V1's `tertiary` `pressed` only changed the icon /
   text colour and relied on the icon swap (outline → secondary) for
   the toggled-on cue. Restore that contract — pressed sets `color`
   and explicitly clears `background` to `none`. Float / Subtle /
   Option inherit the same fix via `variations.tertiary(color)`.

2. Icons shrunk by one full step everywhere.
   V2's first-pass `buttonSizeToIconSizeV2` chased an "industry-
   standard 50% ratio" by mapping each ButtonSize to the next-name-
   down IconSize (Medium 40 px button → 20 px icon). Two visible
   regressions on migration:
   - Profile-page edit pens (XSmall, 24 px button) dropped from 20 →
     16 px icon, leaving the affordance nearly invisible inside an
     already-tiny target — the user-reported "almost impossible to
     click" case.
   - Toolbar Small buttons lost a third of their icon footprint
     (24 → 16 px).
   Restore v1's same-name mapping (XSmall button → XSmall icon, etc.)
   so every migrated call site keeps its v1 visual scale. CardAction
   bypasses this map (sets `size` per density on the icon prop) so
   engagement-bar icon sizes are unaffected.

Co-authored-by: Cursor <cursoragent@cursor.com>
tsahimatsliah and others added 2 commits May 4, 2026 00:38
v2 first-pass scaled `gap` with button size (gap-1 → gap-2.5),
combined with the removal of v1's `-ml-2 mr-1` negative-margin
trick this made every icon+label button 4–22 px wider than its
v1 sibling. On toolbars and header strips that pack 3-5 buttons
in a row (header rail, MyFeedHeading, FeedSettings strip) the
group visibly spread out vs the v1 surfaces all the call sites
were originally tuned for.

Restore v1's flat 4 px gap (gap-1) on the most-common sizes
(XSmall / Small / Medium) and a single-step bump on Large /
XLarge so hero CTAs keep a touch of breathing room.

Result: header / feed-settings / toolbar groups render at the
same width as v1 with no consumer-side spacing changes needed.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ttonV2

Sweep of every remaining v1 `Button` import across `packages/shared/`
(auth forms, modals, sidebars, profile/squad/recruiter surfaces, live
rooms, onboarding, opportunity, organizations, briefing, integrations,
shortcuts, etc.) to `ButtonV2`. Identifier swaps:

- Button       -> ButtonV2
- ButtonProps  -> ButtonV2Props
- ButtonGroup  -> ButtonV2Group

ButtonSize / ButtonVariant / ButtonColor / ButtonIconPosition / IconType
keep the same identifier (re-exported unchanged from ButtonV2).

Wrapper components OptionsButton, UploadButton, and ToggleClickbaitShield
now compose ButtonV2 internally. The 6 PR-1 files that import
`ButtonColor` from the v1 path are re-pointed at ButtonV2 for consistency.

v1 `Button.tsx`, `Button.spec.tsx`, and `QuaternaryButton.tsx` are kept
untouched on this branch — they remain marked `@deprecated` and are still
imported by webapp/extension call sites that PR 3 will migrate. PR 4
deletes the v1 source.

Co-authored-by: Cursor <cursoragent@cursor.com>
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