Repository navigation
refactor(ui): shared ConfirmDialog, @base-ui/react, remove Tailwind and unused deps - #57
Merged
Merged
Conversation
…deps - Move the five base-ui import sites from @base-ui-components/react@1.0.0-rc.0 to @base-ui/react@1.7 (same part names, props and data attributes; className now accepts undefined, so the css() shims go). - Add app/_components/ui/confirm-dialog.tsx + dialog.module.css: one modal shell (backdrop, popup, popupWide, title, description, actions, confirm, cancel) replacing three near-identical dialog stylesheets. - privacy-switch's two confirm dialogs, the artifact delete dialog and the admin delete-account dialog all render through ConfirmDialog; share-dialog reuses the shell. user-table no longer imports CSS from app/a/[id]. - src/lib/ui/class-name.ts exports a single cx() helper. - Remove unused deps: @base-ui-components/react, cmdk, sonner, next-themes, class-variance-authority, clsx. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
No component used a Tailwind utility class (the generated utilities were all matches from prose/comments, shadowed by unlayered app CSS), but every screen was laid out on top of Tailwind's preflight reset. Removing the import alone would have changed rendering (list bullets, heading sizes, button chrome, link underlines, margins). - styles/reset.css is preflight.css from tailwindcss@4.3.3 (MIT), wrapped in @layer base exactly as Tailwind emitted it, with --theme() calls replaced by the values they resolved to. The compiled base layer matches the previous build rule-for-rule. - Drop the @theme inline block (a self-referential mapping only utilities consumed) and postcss.config.mjs; Next's built-in CSS pipeline takes over. - .sr-only gains padding:0 / border-width:0, which Tailwind's own .sr-only utility used to merge in underneath. - Remove tailwindcss and @tailwindcss/postcss. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
datj9
commented
Sep 23, 2026
datj9
left a comment
Owner
Author
There was a problem hiding this comment.
🤖 Automated review (Claude Code)
Verdict: Looks good to merge, once e2e has actually run green. No code defects found.
Findings: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 2 LOW
Checks run locally on d486647 (branch is based on current main):
pnpm install --frozen-lockfile: pass (lockfile consistent after the 848-line removal)pnpm typecheck: passpnpm lint: passpnpm vitest run --project unit: 73 files, 1182 tests passpnpm build: pass. Compiled CSS still contains the@layer baseblock fromstyles/reset.cssand no cascade-layer polyfill (:not(#\#)) output, so removingpostcss.config.mjsand falling back to Next's default PostCSS config did not flatten the layer. Unlayered globals and CSS modules still win over the reset.- grep for
@base-ui-components,clsx,cmdk,sonner,next-themes,class-variance-authority,tailwind, and the removedcss()helper acrossapp/ src/ styles/ tests/ packages/and config files: no remaining imports (only attribution comments inreset.css) - No dangling references to
--dur-share/--dur-delete/--dur-publishor to classes deleted fromshare-dialog.module.css/delete-dialog.module.css.publish-dialog.module.csshas no importers left. - No e2e selector depends on a removed CSS-module class; specs use test ids, and all test ids are kept.
What I checked and found no problem with:
ConfirmDialogcall sites keep test ids, copy,initialFocus/finalFocus, and open/close semantics. Both privacy dialogs still close before callingchoose(). Delete still refreshes the live-link count on open. The admin delete still has no busy/close change (deferred to D1b, as the PR says).- The dialog
.confirmreproduces the.button-smsizing andpointer: coarsepromotion it used to get from the global class. The global:focus-visibleoutline still applies. cx()is correct and tested forundefined/false/null/empty parts.
LOW
- e2e has not run anywhere for this PR. Both
checkruns failed during setup withpull access denied for minio/minio, before any test step ran. This is an infra problem, not caused by this PR. But combined with "did not run e2e locally", the dialog refactor (visibility-*,trash-delete-restore,two-account-privacy,zz-design-system) is still unverified in a browser. Fix the MinIO image reference in the workflow, or re-run once it pulls, before merging. ConfirmDialoghas no component-level test for its own contract:onConfirmis not re-fired whilebusy, the error slot hasrole="alert", andinitialFocusmaps to the right button. The unit project runs inenvironment: 'node', so today only e2e covers this. This is acceptable for a no-behaviour-change refactor. Worth adding once there is a DOM test project, because D1b will start relying on these guarantees.
Docs follow-up (already noted in the PR, not in this diff): design.md:109 still mentions Tailwind v4 exports, and docs/motion.md:113 still says "Toasts: Sonner defaults".
…t.css While busy, Esc, a backdrop press or the cancel button could close the dialog mid-request: a failure then rendered into a closed dialog, and a success landed after the person had cancelled. Close requests are now canceled via base-ui's eventDetails.cancel() (keeps uncontrolled dialogs open) and not forwarded (keeps controlled ones open); Cancel goes aria-disabled. The public props are unchanged. reset.css vendors Tailwind's preflight; MIT requires the permission notice, not only the copyright line, so it is now included in full. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Owner
Author
|
Review of D1a (base-ui migration, ConfirmDialog, Tailwind removal, dep removal). Fixed in 463748b
Checked, no defect
Left as is (pre-existing, behaviour-preserving)
Gates: typecheck, lint, unit (74 files / 1186 tests) and |
datj9
added a commit
that referenced
this pull request
Sep 24, 2026
feat: owner-controls UX — confirmations, shared share state, manual radiogroup (D1b, stacked on #57)
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.
Plan item D1a. A refactor meant to change no behaviour. D1b (
feat/owner-controls-ux) builds on this branch.Dependencies removed
@base-ui-components/react@1.0.0-rc.0@base-ui/react@^1.7.0cmdk,sonner,next-themes,class-variance-authority,clsxtailwindcss,@tailwindcss/postcss,postcss.config.mjsbase-ui migration (
1.0.0-rc.0→@base-ui/react@1.7.0)I compared the
.d.tsfiles of both packages in node_modules for every part we use (Dialog Root/Trigger/Portal/Backdrop/Popup/Title/Description/Close, Menu Root/Trigger/Portal/Positioner/Popup/Item):initialFocus/finalFocus(RefObject form),closeOnClick,render,side/align/sideOffset: unchanged.data-starting-style,data-ending-style,data-open,data-highlighted): unchanged.classNamenow acceptsstring | undefined, so the two copy-pastedcss()shims andsrc/lib/uicss()are gone.initialFocusnow focuses the popup itself when opened by touch; mouse and keyboard still focus the first tabbable element. This affects only the artifact delete dialog and the admin delete-account dialog, and is arguably safer. (2) MenucloseParentOnEscdefault changed. We have no submenus, so this does nothing here.Tailwind removal: how I checked it
Tailwind generated no utilities we used. It emitted a few (
.hidden,.table,.sr-only, …) only because those words appear in comments and prose, and unlayered app CSS or CSS-module hashing shadowed all of them. It did supply preflight, and every screen is laid out on top of it (margins, list bullets, heading sizes, button chrome,a { text-decoration: inherit }). So:styles/reset.cssistailwindcss@4.3.3/preflight.csscopied in (MIT, attributed). It is wrapped in@layer baseexactly as Tailwind emitted it, and each--theme()call is replaced by the value it resolved to.mainand this branch and diffed the compiled CSS. The@layer baseoutput matches rule for rule. The only differences are the html font stack written as a literal (same value) and the::placeholdercurrentColorfallback for browsers withoutcolor-mix, which Tailwind's own lightningcss pass used to add. The:roottoken output is identical.@theme inlineblock. It was a self-referential mapping that only utilities read..sr-onlygainspadding:0; border-width:0, which Tailwind's.sr-onlyutility used to merge in underneath.tests/unit/token-contrast.test.tspasses.New primitives
app/_components/ui/confirm-dialog.tsx:ConfirmDialog. Every prop has a doc comment in the file.app/_components/ui/dialog.module.css: one modal shell (backdrop,popup,popupWide,title,description,actions,confirm,cancel). It replacespublish-dialog.module.css, most ofdelete-dialog.module.css(only the trigger is left), and the duplicated frame inshare-dialog.module.css.src/lib/ui/class-name.ts: a singlecx(...parts)helper. It replacesclsxand thecss()shims, and has unit tests.Call sites: both privacy-switch confirmations are now
<ConfirmDialog>(the two copy-pasted components are removed), and so are the artifact delete dialog and the admin delete-account dialog.user-table.tsxno longer importsapp/a/[id]/delete-dialog.module.css. All test ids, copy, focus targets and open/close semantics are kept.user-tablestill closes on failure and still has nocatch, because that fix belongs to D1b.One small visual change
The publish-public and set-private dialogs used their own button sizing: a 24px padded confirm and a 24px padded cancel with a negative margin. They now use the shared dialog buttons, the same ones the delete dialogs already had: confirm on
--control-sm(32px, promoted to 44px onpointer: coarse) and cancel as a text button with a--control-mdtarget. This lines them up with the control scale indesign.mdandtokens.css.Testing
pnpm install --frozen-lockfile,pnpm typecheck,pnpm lint: passpnpm vitest run --project unit: 73 files, 1182 tests pass (includes newtests/unit/class-name.test.ts)pnpm build(with.env.examplevalues): passes; compiled CSS diffed againstmainas described abovegrepfor every removed package acrossapp/ src/ styles/ tests/ packages/and the config files finds nothingRisks
zz-design-system,visibility-*,share-*,trash-delete-restoreandtwo-account-privacy. They depend only on test ids and visible copy, and I kept both.zz-design-systemmeasures only controls that are rendered, so closed dialogs are skipped.design.md:109(Tailwind v4 exports note) anddocs/motion.md:113("Toasts: Sonner defaults"). I left them unchanged. Worth a docs follow-up.package.json(scripts only). Any conflict should be trivial.🤖 Generated with Claude Code