Skip to content

feat(frontend): land Tamagui toolchain, swap ProgressBar off Radix (#580) - #701

Closed
gaidheal1 wants to merge 4 commits into
developmentfrom
claude/issue-580-progressbar-tamagui
Closed

feat(frontend): land Tamagui toolchain, swap ProgressBar off Radix (#580)#701
gaidheal1 wants to merge 4 commits into
developmentfrom
claude/issue-580-progressbar-tamagui

Conversation

@gaidheal1

Copy link
Copy Markdown
Member

Summary

First real (non-PoC) landing of the Tamagui toolchain decided in #591 for the RN/Expo migration (#578), and the first sub-issue of #578 to ship: closes #580.

ProgressBar moves off @radix-ui/react-progress onto Tamagui's own Progress primitive — confirmed by reading @tamagui/progress's source that it's a genuine fork of Radix's Progress, not a runtime wrapper around it, so this actually satisfies "no @radix-ui/react-progress import remains," not just an import rename.

Toolchain (wired as permanent config, not PoC scaffolding)

ProgressBar

Swapped Progress.Root for Tamagui's Progress with unstyled set, so ProgressBar.module.scss stays the sole source of visual truth — the same role Radix's bare Progress.Root played. The fill stays a plain styled <div>, not Progress's own Indicator, matching the original's design (Radix's Indicator was never used either) and avoiding Indicator's transform-based positioning model, which doesn't match this component's percent-width fill.

A real bug found and fixed, not just a test artifact

Map.tsx renders tooltip content (including ProgressBar, via #673's village-progress tooltip) into a second, independent React root (createRoot(host), for imperative position-tracking) that doesn't inherit main.tsx's <TamaguiProvider> context — React context follows the component tree, not DOM nesting. Without re-providing it at that second root, tapping a village marker would throw in production, not just in tests. Fixed by wrapping that root's render in its own <TamaguiProvider>.

This also means #580's "no in-app consumer" premise is now staleMap/MapTooltips.tsx started consuming ProgressBar via #673, merged after #580 was written. Worth a follow-up comment on #580/#578 to correct the record.

Verification

  • 448/448 unit tests pass (incl. Map.test.tsx, updated to wrap renders in TamaguiProvider)
  • tsc --noEmit clean
  • npm run lint: unchanged from development's existing 14 pre-existing problems (confirmed by diffing against unmodified development, not just eyeballing the count)
  • Production build succeeds. Bundle delta on the index chunk: +431 kB raw / +121 kB gzip (measured directly, both branches built with the same toolchain) — a bit above Spike: PoC Tamagui as the combined primitives + styling choice for #578/#591 #629's PoC estimate (+383/+102), expected since this lands a real component on top of the fixed provider cost, not just the provider itself.

Not verified: Storybook's browser-mode a11y suite (vitest --project storybook) — this sandbox lacks the chrome-headless-shell binary that provider needs. Confirmed pre-existing by reproducing the identical failure on unmodified development, so it isn't a regression from this change, but it means that specific acceptance-criterion item is unverified here rather than passing.

Acceptance criteria (from #580)

  • No @radix-ui/react-progress import remains; role/aria-valuenow/aria-valuemax/aria-label semantics preserved (verified by test)
  • Inside/outside label-fit behaviour still works (unchanged offsetWidth measurement — no native target exists yet to give it an onLayout path)
  • ProgressBar.test.tsx passes
  • ProgressBar.stories.tsx + Storybook a11y addon — not verified, see above
  • Tamagui's Progress semantics (role/aria-valuenow/aria-valuemax) verified directly against real assertions, not inferred from other components

🤖 Generated with Claude Code


Generated by Claude Code

)

First real (non-PoC) landing of the Tamagui toolchain decided in #591
for the RN/Expo migration (#578), and the first sub-issue of #578 to
ship: ProgressBar (#580) moves off @radix-ui/react-progress onto
Tamagui's own Progress primitive (a genuine fork of Radix's, not a
runtime wrapper around it - confirmed by reading @tamagui/progress's
source and package.json before writing this).

Toolchain, wired as permanent config rather than PoC scaffolding:
- tamagui, @tamagui/core, @tamagui/config, @tamagui/vite-plugin,
  react-native-web added; @radix-ui/react-progress removed.
- Pinned to the exact Tamagui version (2.6.0) the epic's PoC findings
  (#629, #583) are based on, rather than drifting to latest - avoids
  re-litigating verified findings against an untested version. (Latest,
  2.7.1, also requires TamaguiProvider's new `defaultTheme` prop, which
  2.6.0's types don't - another reason to stay pinned for now.)
- tamagui.config.ts: @tamagui/config's default preset with breakpoints
  aligned to the app's own SCSS scale (sm/md/mdUp), per #629's findings.
- vite.config.ts: @tamagui/vite-plugin's compiler wired in alongside
  (not replacing) the existing maplibre-gl static-copy workaround.
- <TamaguiProvider> mounted at the app root (main.tsx) and as a
  Storybook global decorator, so future Tamagui-based stories don't
  each need their own wrap.

ProgressBar.tsx: swapped Progress.Root for Tamagui's Progress with
`unstyled` set, so ProgressBar.module.scss stays the sole source of
visual truth - same role Radix's bare Progress.Root played. The fill
stays a plain styled <div>, not Progress's own Indicator, matching the
original's design (Radix's Indicator was never used either) and
avoiding Indicator's transform-based positioning model, which doesn't
match this component's percent-width fill.

Found and fixed a real bug along the way, not just a test artifact:
Map.tsx renders tooltip content (including ProgressBar, via #673's
village-progress tooltip) into a second, independent React root
(createRoot(host), for imperative position-tracking) that doesn't
inherit main.tsx's <TamaguiProvider> context - React context follows
the component tree, not DOM nesting. Without re-providing it at that
second root, tapping a village marker would throw in production, not
just in tests. Fixed by wrapping that root's render in its own
<TamaguiProvider>.

Verified: 448/448 unit tests pass (incl. Map.test.tsx, updated to wrap
renders in TamaguiProvider), tsc --noEmit clean, lint unchanged from
development's pre-existing 14 problems, production build succeeds.
Bundle delta on the index chunk: +431 kB raw / +121 kB gzip (measured
directly, both branches built with the same toolchain) - a bit above
#629's PoC estimate (+383/+102), expected since this lands a real
component on top of the fixed provider cost, not just the provider.

Not verified: Storybook's browser-mode a11y suite (`vitest --project
storybook`) - this sandbox lacks the chrome-headless-shell binary that
provider needs, confirmed pre-existing by reproducing the same failure
on unmodified development.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019tw1wbEwrW3EiTspfBt4RP
@gaidheal1
gaidheal1 marked this pull request as draft August 6, 2026 13:36
@gaidheal1 gaidheal1 self-assigned this Aug 14, 2026
claude and others added 3 commits August 14, 2026 14:26
)

First real (non-PoC) landing of the Tamagui toolchain decided in #591
for the RN/Expo migration (#578), and the first sub-issue of #578 to
ship: ProgressBar (#580) moves off @radix-ui/react-progress onto
Tamagui's own Progress primitive (a genuine fork of Radix's, not a
runtime wrapper around it - confirmed by reading @tamagui/progress's
source and package.json before writing this).

Toolchain, wired as permanent config rather than PoC scaffolding:
- tamagui, @tamagui/core, @tamagui/config, @tamagui/vite-plugin,
  react-native-web added; @radix-ui/react-progress removed.
- Pinned to the exact Tamagui version (2.6.0) the epic's PoC findings
  (#629, #583) are based on, rather than drifting to latest - avoids
  re-litigating verified findings against an untested version. (Latest,
  2.7.1, also requires TamaguiProvider's new `defaultTheme` prop, which
  2.6.0's types don't - another reason to stay pinned for now.)
- tamagui.config.ts: @tamagui/config's default preset with breakpoints
  aligned to the app's own SCSS scale (sm/md/mdUp), per #629's findings.
- vite.config.ts: @tamagui/vite-plugin's compiler wired in alongside
  (not replacing) the existing maplibre-gl static-copy workaround.
- <TamaguiProvider> mounted at the app root (main.tsx) and as a
  Storybook global decorator, so future Tamagui-based stories don't
  each need their own wrap.

ProgressBar.tsx: swapped Progress.Root for Tamagui's Progress with
`unstyled` set, so ProgressBar.module.scss stays the sole source of
visual truth - same role Radix's bare Progress.Root played. The fill
stays a plain styled <div>, not Progress's own Indicator, matching the
original's design (Radix's Indicator was never used either) and
avoiding Indicator's transform-based positioning model, which doesn't
match this component's percent-width fill.

Found and fixed a real bug along the way, not just a test artifact:
Map.tsx renders tooltip content (including ProgressBar, via #673's
village-progress tooltip) into a second, independent React root
(createRoot(host), for imperative position-tracking) that doesn't
inherit main.tsx's <TamaguiProvider> context - React context follows
the component tree, not DOM nesting. Without re-providing it at that
second root, tapping a village marker would throw in production, not
just in tests. Fixed by wrapping that root's render in its own
<TamaguiProvider>.

Verified: 448/448 unit tests pass (incl. Map.test.tsx, updated to wrap
renders in TamaguiProvider), tsc --noEmit clean, lint unchanged from
development's pre-existing 14 problems, production build succeeds.
Bundle delta on the index chunk: +431 kB raw / +121 kB gzip (measured
directly, both branches built with the same toolchain) - a bit above
component on top of the fixed provider cost, not just the provider.

Not verified: Storybook's browser-mode a11y suite (`vitest --project
storybook`) - this sandbox lacks the chrome-headless-shell binary that
provider needs, confirmed pre-existing by reproducing the same failure
on unmodified development.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019tw1wbEwrW3EiTspfBt4RP
….com/progressrpg/ProgressRPG into claude/issue-580-progressbar-tamagui

# Conflicts:
#	frontend/.storybook/preview.tsx
#	frontend/package-lock.json
#	frontend/package.json
#	frontend/src/components/Map/Map.test.tsx
#	frontend/src/components/ProgressBar/ProgressBar.test.tsx
#	frontend/src/components/ProgressBar/ProgressBar.tsx
@gaidheal1
gaidheal1 marked this pull request as ready for review August 14, 2026 13:47
@gaidheal1
gaidheal1 changed the base branch from development to main August 14, 2026 13:51
@gaidheal1
gaidheal1 changed the base branch from main to development August 14, 2026 13:51
@gaidheal1 gaidheal1 closed this Aug 14, 2026
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.

2 participants