fix(components): resizable is a diverged file, not a synced one — stop the sync from breaking the build, and finish the v4 migration in it - #3029
Merged
Conversation
…p the sync from breaking the build, and finish the v4 migration in it `ui/resizable.tsx` looks like a Shadcn-synced no-touch file (AGENTS.md #7). It is not one, and has not been since `00b61d6d8` ("upgrade shadcn components and fix build issues") hand-migrated its imports from v3's `import * as ResizablePrimitive` to v4's `{ Group, Panel, Separator }`. Upstream never followed. Both registry endpoints — `styles/default` and `styles/new-york` — still serve the v3 file, which reaches for `ResizablePrimitive.PanelGroup` and `PanelResizeHandle`. Neither name exists in react-resizable-panels v4.12.2: it exports only `Group`, `Panel` and `Separator`. So `pnpm shadcn:update-all` — an advertised script — overwrites this file with code that cannot compile. The commit title above is what that looks like after the fact; it has already happened once. Defused by listing `resizable` under `customComponents` in `shadcn-components.json`, which is the manifest's existing mechanism for this: `--update-all` iterates `Object.keys(manifest.components)`, and `--update resizable` now refuses with "not found in Shadcn registry". With the file no longer synced, the v4 fix belongs in it rather than in a wrapper built to avoid touching it. #3024 added `custom/resizable.tsx` to re-key the stacked-divider styles off the dead `data-[panel-group-direction=vertical]` and onto the `aria-orientation` attribute v4 actually emits — 8 compensating classes shadowing 8 dead ones in a file one import away. Those 8 now live in `ui/resizable.tsx` directly and `custom/resizable.tsx` is a plain re-export, kept as the sole public export site because `src/index.ts` star-exports `./ui` and `./custom` side by side and exporting `Resizable*` from both collides (TS2308). The group's `data-[panel-group-direction=vertical]:flex-col` is dropped outright: v4 writes `flex-direction: row | column` as an inline style off `orientation`, which outranks any class. Behaviour is unchanged, and provably so — diffing the merged class string before against after yields exactly the 8 dead selectors removed and nothing added, with `tailwind-merge` dropping none of the 23 survivors now that base and variants share one `cn()` call. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-zhuang
added a commit
that referenced
this pull request
Jul 30, 2026
… serves, and refuses to write a file when it cannot (#3033) `updateComponent` rewrote two alias shapes: `@/lib/utils` and `@/components/ui/x`. Surveying all 46 registry entries this manifest points at, the second one **never appears**. Shadcn moved to a different layout, and what it serves today is: 42 components @/lib/utils ← rewritten 8 components @/registry/default/ui/<name> ← missed 2 components @/registry/default/hooks/<name> ← missed 1 component @/registry/new-york/ui/<name> ← missed 1 component @/registry/default/lib/<name> ← missed So syncing `calendar`, `carousel`, `command`, `form`, `pagination`, `sidebar`, `toggle-group` or `chart` left `@/registry/...` specifiers that do not resolve from `src/ui/` — the script swapped working code for code that cannot compile, and said `✓ Updated`. That is how `resizable` ended up hand-patched and eventually reclassified (#3029). Two changes: **The rewrite table now covers what is served.** `ui/` maps to a sibling (`./x`), `hooks/` and `lib/` step up a level (`../hooks/x`, `../lib/x`), across any `<style>` segment. The older `@/components/ui/x` and `@/hooks/x` forms stay in the table so a re-pointed source keeps working. Matching is on the quoted specifier rather than on `from "…"`, so `export … from`, dynamic `import()` and `vi.mock()` are covered. **It fails closed.** Any `@/…` left after rewriting is now a hard refusal to write, naming the specifier and pointing at the table. An enumerated list of paths silently goes stale the next time Shadcn reorganises; the guard is what makes that visible instead of catastrophic. Verified with a hypothetical future layout (`@/registry/tokyo/blocks/button`): flagged, while known aliases still rewrite. Also: `--check` and `--diff` now rewrite before comparing, so import-path style alone no longer reads as drift, and `--diff` warns when `--update` would refuse. A registry entry shipping more than one file (`toast` ships 3) now says which files it is not writing rather than silently dropping them. Verified against all 46 live registry entries: every one rewrites to zero unmapped aliases, and every rewritten relative specifier resolves on disk. End-to-end `--update sidebar` — the entry exercising all three shapes — now reproduces the import block already on main **exactly**, zero difference; the remaining 21/-24 line delta is genuine upstream drift in the component body. Restored afterwards; no component file changes here. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 5 <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.
Follow-up to #3025. The plan was to re-sync
ui/resizable.tsxfrom upstream Shadcn and delete the compensation wrapper #3024 added. That turned out to be impossible, and the sync script is actively dangerous today. This PR fixes the danger and gets the same cleanup a different way.Re-syncing would break the build
#3024's note claimed upstream had been regenerated for v4. It has not. Both registry endpoints still serve the v3 file:
data-[panel-group-direction]r/styles/default/resizable.jsonResizablePrimitive.PanelGroup/PanelResizeHandler/styles/new-york/resizable.jsonResizablePrimitive.PanelGroup/PanelResizeHandleNeither name exists in
react-resizable-panels@4.12.2— it exports onlyGroup,Panel,Separator;PanelGroupandPanelResizeHandleappear zero times in its declarations. Sopnpm shadcn:update-all, an advertised script, overwrites this file with code that cannot compile.This has already happened once.
ui/resizable.tsxhas been diverged since00b61d6d8— titled "fix: upgrade shadcn components and fix build issues" — which is the hand-fix convertingimport * as ResizablePrimitive→import { Group, Panel, Separator }after a bulk sync ran.Defusing it
resizablemoves fromcomponentstocustomComponentsinshadcn-components.json— the manifest's existing mechanism for exactly this. Verified against the script:--update-alliteratesObject.keys(manifest.components)(line 287), which no longer contains it--update resizablenow refuses:Component "resizable" not found in Shadcn registry (might be custom)Finishing the migration in the file itself
With the file no longer synced, the fix belongs in it rather than in a wrapper built to avoid touching it. The 8
aria-[orientation=horizontal]classes #3024 put incustom/resizable.tsxmove intoui/resizable.tsx, replacing the 8 deaddata-[panel-group-direction=vertical]ones they were shadowing from one import away.custom/resizable.tsxbecomes a plain re-export. It stays as the sole public export site —src/index.tsstar-exports./uiand./customside by side, so exportingResizable*from both would collide (TS2308).ResizableHandlePropsis preserved rather than dropped: it has no in-repo consumers, but it is public API via the package root.The group's
data-[panel-group-direction=vertical]:flex-colis dropped outright — v4 writesflexDirection: c === "horizontal" ? "row" : "column"as an inline style, which outranks any class.On AGENTS.md #7
This edits a file under
packages/components/src/ui/. The rule scopes itself to "upstream 3rd-party files overwritten by sync scripts" — after this PR the file is neither. Its new header says so, loudly, along with how to undo the whole arrangement if upstream ever regenerates for v4.Behaviour is unchanged, provably
Diffing the merged class string before vs. after: exactly the 8 dead selectors removed, 0 added, everything else byte-identical.
The one real risk in merging base and variant classes into a single
cn()wastailwind-mergeeating a base utility. It does not — all 23 classes survive (variant-prefixed utilities don't conflict with bare ones).Verification
pnpm --filter @object-ui/components type-check— cleanpnpm --filter @object-ui/app-shell type-check— cleanresizable-orientation(15 tests) green unmoved, including the "only keys on attributes the installed library actually emits" guard, which proves the 8 variants still match the real DOM from their new homedist/custom/resizable.d.ts(all 4 names)No changeset — internal cleanup, no public API change.
🤖 Generated with Claude Code