Skip to content

feat(ui): extract shared form and overlay primitives - #617

Merged
zacjones93 merged 53 commits into
codex/ui-package-foundationfrom
codex/ui-form-overlay-primitives
Jul 15, 2026
Merged

feat(ui): extract shared form and overlay primitives#617
zacjones93 merged 53 commits into
codex/ui-package-foundationfrom
codex/ui-form-overlay-primitives

Conversation

@zacjones93

@zacjones93 zacjones93 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • extract the byte-identical generic checkbox, dialog, dropdown-menu, form, popover, radio-group, select, sheet, tabs, and tooltip implementations into direct @repo/ui subpaths
  • preserve every Start and Crew import through explicit compatibility re-exports; searchable-select, sidebar, command, switch, and domain components remain out of scope
  • add interaction-driven Storybook coverage plus exact export/identity and accessible render tests
  • pin the package React peer/dev resolution to the Start and Crew 19.2.3 runtime and update the checked-in inventory/LAT contract

Stack

  • base: codex/ui-package-foundation
  • head: codex/ui-form-overlay-primitives

Validation

  • Node 24.15.0 / Corepack pnpm 9.12.1
  • @repo/ui build, type-check, lint, and 24 tests
  • Start and Crew type-checks
  • Storybook dev smoke and static build
  • clean light/dark Canvas and Docs browser smoke with form, select, radio, checkbox, tabs, dialog, menu, popover, sheet, and tooltip interactions
  • UI inventory regeneration/check
  • lat check
  • full pre-push lint and workspace type-check
  • route no-churn and diff checks

The package build currently emits ignored JavaScript artifacts only; declaration output is not configured. Start and Crew application builds stop at the expected missing ignored .alchemy/local/wrangler.jsonc files, and this PR does not generate deployment state.


Summary by cubic

Extracted shared form and overlay primitives into @repo/ui subpaths and replaced app-local copies with thin re-exports. Added Storybook coverage and tests, and applied review feedback for styling and docs/inventory updates.

  • New Features

    • New @repo/ui exports: checkbox, dialog, dropdown-menu, form, popover, radio-group, select, sheet, tabs, tooltip.
    • Start and Crew keep existing import paths via compatibility re-exports.
    • Storybook stories with interaction tests for dialog/sheet, dropdown-menu/popover/tooltip, form, and tabs.
    • Compatibility and accessibility tests to ensure export parity and behavior.
  • Dependencies

    • Pinned React peer/dev for @repo/ui to 19.2.3.
    • Added Radix deps: @radix-ui/react-checkbox, @radix-ui/react-dialog, @radix-ui/react-dropdown-menu, @radix-ui/react-popover, @radix-ui/react-radio-group, @radix-ui/react-select, @radix-ui/react-tooltip.

Written for commit 31ed97c. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added shared, reusable UI components for checkboxes, dialogs, menus, forms, popovers, selections, sheets, tabs, tooltips, and radio groups.
    • Expanded UI package entry points for consistent component access across the application.
    • Added interactive Storybook examples for dialogs, sheets, menus, forms, and tabs.
  • Tests

    • Added accessibility and interaction coverage for checkbox and dialog behavior.
    • Expanded compatibility checks across shared UI components.
  • Documentation

    • Updated UI library ownership, compatibility, and Storybook coverage guidance.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The shared @repo/ui package now provides Radix-based primitives for controls, overlays, forms, and navigation. Crew and Start adapters re-export these components, with expanded package exports, compatibility tests, Storybook interaction stories, and updated migration documentation.

Changes

Shared UI migration

Layer / File(s) Summary
Package exports and dependencies
packages/ui/package.json
Adds component subpath exports and dependencies for the shared UI primitives.
Shared control primitives
packages/ui/src/components/{checkbox,radio-group,select,tabs}.tsx
Adds styled Radix wrappers for checkbox, radio, select, and tabs components.
Shared overlay primitives
packages/ui/src/components/{dialog,dropdown-menu,popover,sheet,tooltip}.tsx
Adds shared dialog, menu, popover, sheet, and tooltip implementations with portals, styling, and forwarded refs.
Shared form primitives
packages/ui/src/components/form.tsx
Adds form context, controller integration, generated IDs, accessibility attributes, and validation messages.
Application adapter re-exports
apps/crew/src/components/ui/*, apps/wodsmith-start/src/components/ui/*
Replaces local implementations with re-exports from @repo/ui.
Compatibility tests and Storybook coverage
packages/ui/test/*, apps/wodsmith-start/src/components/ui/*.stories.tsx
Expands adapter parity checks and adds interactive stories and primitive tests.
Migration inventory and contract documentation
apps/wodsmith-start/docs/ui-library-inventory.md, apps/wodsmith-start/scripts/generate-ui-library-inventory.mjs, lat.md/ui-library.md
Updates ownership, packaging, compatibility, story coverage, and PR-3 migration guidance.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Storybook
  participant AppAdapter
  participant SharedDialog
  participant RadixDialog
  Storybook->>AppAdapter: Render dialog story
  AppAdapter->>SharedDialog: Re-exported Dialog components
  SharedDialog->>RadixDialog: Open and close dialog primitives
  RadixDialog-->>Storybook: Render accessible dialog state
Loading

Poem

A bunny hops through shared UI bright,
Radix buttons bloom in one package light.
Apps point their paths to components anew,
Stories test what the users do.
“Boing!” says the rabbit—exports align!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main refactor: extracting shared UI primitives, including form and overlay-related components, into the shared package.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/ui-form-overlay-primitives

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zacjones93

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
apps/wodsmith-start/src/components/ui/dialog.stories.tsx (1)

99-108: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the sheet closes after clicking "Done".

The EditingSheet play function clicks the "Done" button but doesn't verify the sheet is removed from the DOM, unlike ConfirmationDialog which asserts dialog is removed after Cancel. Add the missing close assertion for parity.

💚 Proposed fix
     await userEvent.click(within(dialog).getByRole("button", { name: "Done" }))
+    await expect(dialog).not.toBeInTheDocument()
   },
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/wodsmith-start/src/components/ui/dialog.stories.tsx` around lines 99 -
108, Update the EditingSheet play function to verify the dialog closes after
clicking the “Done” button. Using the existing dialog reference and testing
utilities, assert that the dialog is removed from the DOM, matching the close
assertion used by ConfirmationDialog.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/package.json`:
- Around line 58-60: Add react-dom to the peerDependencies object alongside
react in the package metadata, using a compatible React 19 version range
consistent with the existing react declaration.

In `@packages/ui/src/components/form.tsx`:
- Around line 43-52: Update useFormField to validate the context before calling
getFieldState: check whether fieldContext.name is missing, throw the existing
“useFormField should be used within <FormField>” error, then retrieve field
state only after validation. This avoids the ineffective truthiness check caused
by FormFieldContext’s default value.

In `@packages/ui/src/components/popover.tsx`:
- Line 1: Add the "use client" directive at the top of the popover component
module, before the `@radix-ui/react-popover` import, matching the client-component
setup used by dialog.tsx, dropdown-menu.tsx, and sheet.tsx.

In `@packages/ui/src/components/select.tsx`:
- Around line 1-5: Add the "use client" directive at the very top of select.tsx,
before the React and Radix imports, so the Select components using client-only
hooks and portals are treated as client components.

In `@packages/ui/test/primitives.test.tsx`:
- Line 18: Add exactly one nearby `// `@lat`:` comment for each `it(...)` test in
`packages/ui/test/primitives.test.tsx`, including the test named “exposes an
accessible labeled checkbox with checked state” and the other test in the file;
use the existing project convention for the reference value and avoid adding
duplicates.

---

Nitpick comments:
In `@apps/wodsmith-start/src/components/ui/dialog.stories.tsx`:
- Around line 99-108: Update the EditingSheet play function to verify the dialog
closes after clicking the “Done” button. Using the existing dialog reference and
testing utilities, assert that the dialog is removed from the DOM, matching the
close assertion used by ConfirmationDialog.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7bdb43f1-582b-49ae-a5d9-5ce0b84a3eea

📥 Commits

Reviewing files that changed from the base of the PR and between a0b1e25 and fcbbd01.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • apps/crew/src/components/ui/checkbox.tsx
  • apps/crew/src/components/ui/dialog.tsx
  • apps/crew/src/components/ui/dropdown-menu.tsx
  • apps/crew/src/components/ui/form.tsx
  • apps/crew/src/components/ui/popover.tsx
  • apps/crew/src/components/ui/radio-group.tsx
  • apps/crew/src/components/ui/select.tsx
  • apps/crew/src/components/ui/sheet.tsx
  • apps/crew/src/components/ui/tabs.tsx
  • apps/crew/src/components/ui/tooltip.tsx
  • apps/wodsmith-start/docs/ui-library-inventory.md
  • apps/wodsmith-start/scripts/generate-ui-library-inventory.mjs
  • apps/wodsmith-start/src/components/ui/checkbox.tsx
  • apps/wodsmith-start/src/components/ui/dialog.stories.tsx
  • apps/wodsmith-start/src/components/ui/dialog.tsx
  • apps/wodsmith-start/src/components/ui/dropdown-menu.stories.tsx
  • apps/wodsmith-start/src/components/ui/dropdown-menu.tsx
  • apps/wodsmith-start/src/components/ui/form.stories.tsx
  • apps/wodsmith-start/src/components/ui/form.tsx
  • apps/wodsmith-start/src/components/ui/popover.tsx
  • apps/wodsmith-start/src/components/ui/radio-group.tsx
  • apps/wodsmith-start/src/components/ui/select.tsx
  • apps/wodsmith-start/src/components/ui/sheet.tsx
  • apps/wodsmith-start/src/components/ui/tabs.stories.tsx
  • apps/wodsmith-start/src/components/ui/tabs.tsx
  • apps/wodsmith-start/src/components/ui/tooltip.tsx
  • lat.md/ui-library.md
  • packages/ui/package.json
  • packages/ui/src/components/checkbox.tsx
  • packages/ui/src/components/dialog.tsx
  • packages/ui/src/components/dropdown-menu.tsx
  • packages/ui/src/components/form.tsx
  • packages/ui/src/components/popover.tsx
  • packages/ui/src/components/radio-group.tsx
  • packages/ui/src/components/select.tsx
  • packages/ui/src/components/sheet.tsx
  • packages/ui/src/components/tabs.tsx
  • packages/ui/src/components/tooltip.tsx
  • packages/ui/test/compatibility.test.ts
  • packages/ui/test/primitives.test.tsx

Comment thread packages/ui/package.json
Comment thread packages/ui/src/components/form.tsx
Comment thread packages/ui/src/components/popover.tsx
Comment thread packages/ui/src/components/select.tsx
Comment thread packages/ui/test/primitives.test.tsx

Copy link
Copy Markdown
Contributor Author

Independent stacked-diff audit: changes requested

Audited exactly a0b1e251850c6d7438cdf4095230708e2263dbdb...fcbbd01f46f9a24ab1f4b6f94e2b03af7fb28164 (41 files; no route/router/auth/server churn).

Findings

  1. [P2] @repo/ui is missing its newly required react-dom peer contract.

    • This diff adds portal-based Radix Dialog, DropdownMenu, Popover, Select, Sheet, and Tooltip exports, but peerDependencies declares only react; react-dom is only a dev dependency.
    • Current Start, Crew, and @repo/ui installs all resolve the same real react@19.2.3 / react-dom@19.2.3, so the monorepo happens to work. The package metadata is still not dependency-closed for another workspace consumer.
    • CodeRabbit's react-dom comment is valid; add a compatible React 19 peer range.
  2. [P2] The newly extracted Tabs story fails WCAG AA contrast in light mode.

    • Storybook's axe panel reports a serious color-contrast violation on the inactive tab: #78716c over #f5f5f4 = 4.39:1, below the required 4.5:1.
    • Dark Tabs passes. Menus/popovers pass in both themes.
    • The new dialog/sheet/form stories also expose 2.68:1 primary-button contrast, but that Button/theme implementation belongs to stacked base PR feat(ui): add shared package foundation #616; I am recording it as stack-base debt rather than attributing it to this exact diff.
  3. [P3] The EditingSheet play function does not assert its close result.

    • Clicking Done closes correctly in the fresh browser smoke and returns focus, but the play function stops after the click. CodeRabbit's suggested expect(dialog).not.toBeInTheDocument() is a valid low-cost coverage improvement.

CodeRabbit triage

  • Valid: react-dom peer dependency; EditingSheet close assertion.
  • Real but inherited/non-blocking for this compatibility extraction: useFormField's dead guard. It is byte-identical inherited behavior; harden separately if intentionally deviating from parity.
  • Not a current-contract blocker: missing "use client" in Popover/Select. Current consumers are TanStack/Vite, the base app implementations are identical, and fresh static/browser execution passes. Revisit if @repo/ui gains a Next/RSC consumer.
  • Not valid under the LAT contract: nearby @lat: comments are required only for documented test-spec leaf sections under require-code-mention. No such leaf specs exist here, and lat check passes.

Evidence

  • Adapter identity: pnpm --filter @repo/ui test24/24 passed, including exact Start/Crew export-name and runtime-object identity checks.
  • Package: pnpm --filter @repo/ui build, type-check, and lint all pass.
  • Consumers/workspace: Start and Crew focused type-checks pass; root pnpm lint and pnpm type-check pass.
  • Dependency boundary: source imports are only declared Radix/React/form/style utilities; no app alias, route, router, auth, server, DB, or feature imports.
  • React: Start, Crew, and @repo/ui resolve the same physical 19.2.3 files. Static Storybook's preview iframe bundles React 19.2.3 with no hook/runtime errors; Storybook's separate manager dependency context retains 19.2.4.
  • Storybook: fresh static build in /tmp/pr617-storybook.xT5Vzl; all 5 new Canvas stories and all 4 Docs pages load in light/dark with no page errors. Dialog/sheet/menu/popover/tooltip portals, keyboard open/escape, focus trapping/return, form controls, checkbox keyboard toggle, and Tabs arrow-key selection work.
  • Inventory/LAT: pnpm --filter wodsmith-start check:ui-inventory and lat check pass.
  • App builds locally reproduce only the documented missing ignored .alchemy/local/wrangler.jsonc limitation; configured CI builds pass.
  • E2E attempt 1 failed before extracted interactions because the untouched registration sidebar did not render Register now; attempt 2 passed. All live PR checks are now green.
  • Both the branch worktree and detached audit worktree are clean.

No files were edited, committed, or pushed.

@zacjones93

Copy link
Copy Markdown
Contributor Author

Follow-up pushed in 31ed97c.

  • added the react-dom peer while keeping package React and React DOM dev resolution at 19.2.3
  • hardened useFormField before getFieldState and added the misuse regression test
  • added use client to Popover and Select
  • added the EditingSheet removal assertion
  • changed only the shared inactive Tabs text class to text-foreground/70

Validation: @repo/ui build/type-check/lint and 25 tests pass; Start/Crew type-checks pass; Storybook static/dev smoke passes; Tabs axe reports 0 violations in light and dark and keyboard/click selection passes; EditingSheet reports all 5 interaction steps passing and returns focus after close; inventory, LAT, route/diff checks, and full pre-push pass.

The previously documented primary-button contrast finding remains inherited stack-base debt and is intentionally unchanged for the separate reviewed layer.

Copy link
Copy Markdown
Contributor Author

Independent re-review: LGTM

Re-audited follow-up fcbbd01f46f9a24ab1f4b6f94e2b03af7fb28164..31ed97c7c453a861176921da695cca69c5f7e782 and the full stacked diff a0b1e251850c6d7438cdf4095230708e2263dbdb...31ed97c7c453a861176921da695cca69c5f7e782. No remaining findings.

Verified:

  • @repo/ui now declares both react and react-dom peers at ^19.2.3; Start, Crew, and the package resolve the same physical react@19.2.3 and react-dom@19.2.3 runtime files.
  • useFormField checks for a missing field name before getFieldState; the focused misuse regression returns the intended diagnostic.
  • Popover and Select now carry "use client".
  • EditingSheet asserts removal; fresh Storybook reports all 5 interaction steps passing, the sheet closed, and focus returned to Edit division.
  • Tabs light and dark each report 0 axe violations / 18 passes / 0 inconclusive. ArrowRight moves selection and focus to Schedule and renders Heat schedule content.
  • pnpm --filter @repo/ui build, type-check, lint, and 25/25 tests pass.
  • Start/Crew type-checks, UI inventory, lat check, and both delta/full git diff --check pass.
  • The full stack remains 41 files with no route/router/auth/server churn.
  • All five CodeRabbit threads are resolved, and each author reply matches the code and LAT contract.
  • Both branch and detached audit worktrees are clean.

Live CI has no failures: all build, lint, typecheck, test, both E2E shards, and Crew E2E jobs pass. Only the final E2E merge-reports job remains in progress at the time of this comment.

The previously noted primary-button contrast issue remains inherited stack-base debt from #616 and is not introduced by this PR delta.

No files were edited, committed, or pushed during this re-review.

@zacjones93 zacjones93 closed this Jul 15, 2026
@zacjones93
zacjones93 merged commit d6316c1 into codex/ui-package-foundation Jul 15, 2026
53 of 264 checks passed
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