Skip to content

Commit 9369d4b

Browse files
os-zhuangclaude
andauthored
docs(components): document the remaining nine Shadcn divergences — every tracked component now says why it diverges (#3059)
Completes the triage. All 17 locally-modified components now carry a `localEdits` note; `--check` reports 0 UNDOCUMENTED. None of the nine are droppable either. Like the first eight, every one is a deliberate fix or API extension: command ADR-0054 C4 `contentProps` + the `sr-only` DialogTitle Radix requires. Upstream drops each addition with its usages, so a sync deletes ~38 lines and still type-checks — verified. select Wraps Root to swallow `onValueChange("")`. Radix's hidden native mirror registers options a commit after the trigger, so a value arriving mid-hydration echoes back empty and wipes the field, latching forms whose `visibleWhen` reads it (#2968). table `containerClassName`, to stop the wrapper becoming a second height-unbounded scroll container inside DataTable. chart `block … w-full` instead of `flex justify-center`, or ResponsiveContainer measures no width and charts draw axes with no marks (#1634, 9b16317); plus hand-written Recharts prop types that actually type-check (2e11aa7). sidebar Tailwind v4 syntax, a `data-collapsible`-always-present refactor, and an `eslint-disable react-hooks/purity` the random skeleton width needs. badge `whitespace-nowrap`, or CJK labels break per-character in a cramped table cell (objectui#2762 P0-1). slider Forwards `aria-label` to the Thumb. sheet `hideOverlay` prop. calendar Tailwind v4 syntax on `--cell-size`. Two claims I checked rather than asserted, because both could have shipped as confident wrong statements: - Removing sidebar's `eslint-disable` really does fail Lint — it is an error from `react-hooks/purity`, not a warning, and Lint gates CI. - `theme(spacing.4)` → `1rem` is **cosmetic**, not a fix. Tailwind 4.3.3 still resolves the v3 dot-notation, and both spellings compile to the identical `calc(var(--sidebar-width-icon) + 1rem)`. The note says so; only the `[--var]` → `(--var)` half of that migration is load-bearing. Also corrects a misleading `--check` label. The counts are set differences, so a locally-edited line appears on BOTH sides — once as ours, once as the upstream original it replaced. Calling that "N upstream line(s) pending" reads as updates waiting to be collected, which is how I misread sidebar's 21 as reclaimable work; it is mostly the mirror image of sidebar's own edits. Now "N not matching upstream verbatim". The `outdated` bucket keeps its wording — there `localOnly` is 0, so the count genuinely is new upstream work. Manifest and script only; no component source changes. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 056faa8 commit 9369d4b

2 files changed

Lines changed: 24 additions & 10 deletions

File tree

packages/components/shadcn-components.json

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
"badge": {
5454
"source": "https://ui.shadcn.com/r/styles/default/badge.json",
5555
"dependencies": [],
56-
"registryDependencies": []
56+
"registryDependencies": [],
57+
"localEdits": "Adds `whitespace-nowrap`: a badge is a single-line pill by definition, and without it CJK labels (e.g. 待审批) break per-character inside a cramped table cell and stack vertically (objectui#2762 P0-1). The reasoning is also comment-documented in the file."
5758
},
5859
"breadcrumb": {
5960
"source": "https://ui.shadcn.com/r/styles/default/breadcrumb.json",
@@ -75,7 +76,8 @@
7576
],
7677
"registryDependencies": [
7778
"button"
78-
]
79+
],
80+
"localEdits": "Tailwind v4 syntax: upstream still ships v3’s `[--var]` arbitrary values, which on Tailwind 4.x compile to a bare custom-property name instead of `var(--var)` — invalid CSS that browsers drop. Applied repo-wide in 925051db6. Here it covers `h-`, `w-`, `px-`, `size-` and `max-w-` on `--cell-size`."
7981
},
8082
"card": {
8183
"source": "https://ui.shadcn.com/r/styles/default/card.json",
@@ -97,7 +99,8 @@
9799
"recharts",
98100
"lucide-react"
99101
],
100-
"registryDependencies": []
102+
"registryDependencies": [],
103+
"localEdits": "Three local edits. (1) The container is `block … w-full` rather than upstream’s `flex justify-center`: a flex box gives ResponsiveContainer no measurable width, so charts render axes but no marks (#1634, commit 9b163173b). (2) Tooltip/Legend props are hand-written instead of derived from Recharts’ own types, which did not type-check here (2e11aa72f). (3) Tailwind v4 syntax: upstream still ships v3’s `[--var]` arbitrary values, which on Tailwind 4.x compile to a bare custom-property name instead of `var(--var)` — invalid CSS that browsers drop. Applied repo-wide in 925051db6."
101104
},
102105
"checkbox": {
103106
"source": "https://ui.shadcn.com/r/styles/default/checkbox.json",
@@ -120,7 +123,8 @@
120123
],
121124
"registryDependencies": [
122125
"dialog"
123-
]
126+
],
127+
"localEdits": "Two local additions to CommandDialog. (1) `contentProps`, so callers can attach a stable locator/ARIA name to the underlying dialog element — a `data-testid` spread onto CommandDialog lands on the Radix Dialog root, which renders no DOM (ADR-0054 C4). (2) `sr-only` DialogTitle/DialogDescription, which Radix requires for an accessible name. Upstream has neither, and drops each addition together with its usages — so syncing deletes ~38 lines and still type-checks clean. Verified: `--update command --force` compiles."
124128
},
125129
"context-menu": {
126130
"source": "https://ui.shadcn.com/r/styles/default/context-menu.json",
@@ -248,7 +252,8 @@
248252
"dependencies": [
249253
"radix-ui"
250254
],
251-
"registryDependencies": []
255+
"registryDependencies": [],
256+
"localEdits": "Wraps SelectPrimitive.Root to swallow `onValueChange(\"\")`. Radix mirrors the value into a hidden native `<select>`; SelectContent registers its options a commit AFTER the trigger mounts, so a value arriving mid-hydration (an edit form whose record lands after first paint) finds no matching `<option>`, and Radix echoes back an empty string that silently wipes the field — latching the form when a `visibleWhen` predicate reads it (#2968). SelectItem rejects `value=\"\"`, so `\"\"` is never a real user choice. Also tailwind v4 syntax: upstream still ships v3’s `[--var]` arbitrary values, which on Tailwind 4.x compile to a bare custom-property name instead of `var(--var)` — invalid CSS that browsers drop. Applied repo-wide in 925051db6."
252257
},
253258
"separator": {
254259
"source": "https://ui.shadcn.com/r/styles/default/separator.json",
@@ -262,7 +267,8 @@
262267
"dependencies": [
263268
"radix-ui"
264269
],
265-
"registryDependencies": []
270+
"registryDependencies": [],
271+
"localEdits": "Adds a `hideOverlay` prop that suppresses `<SheetOverlay />`, for sheets that must not dim the page behind them. Upstream renders the overlay unconditionally."
266272
},
267273
"sidebar": {
268274
"source": "https://ui.shadcn.com/r/styles/default/sidebar.json",
@@ -275,7 +281,8 @@
275281
"sheet",
276282
"skeleton",
277283
"tooltip"
278-
]
284+
],
285+
"localEdits": "Three systematic edits, not 24 independent ones. (1) Tailwind v4 syntax: upstream still ships v3’s `[--var]` arbitrary values, which on Tailwind 4.x compile to a bare custom-property name instead of `var(--var)` — invalid CSS that browsers drop. Applied repo-wide in 925051db6. (2) `theme(spacing.4)` → `1rem`: cosmetic only — verified that Tailwind 4.3.3 still resolves the v3 `theme()` dot-notation, and both spellings compile to the identical `calc(var(--sidebar-width-icon) + 1rem)`. Unlike (1) this one is NOT load-bearing; it is just avoiding a deprecated idiom. (3) `data-collapsible` is set unconditionally and each rule qualified with `group-data-[state=collapsed]:`, where upstream blanks the attribute when expanded — same result, but the attribute stays in the DOM for styling and test locators. Also carries an `eslint-disable react-hooks/purity` the skeleton’s random width needs under this repo’s lint config; syncing removes it and Lint fails."
279286
},
280287
"skeleton": {
281288
"source": "https://ui.shadcn.com/r/styles/default/skeleton.json",
@@ -287,7 +294,8 @@
287294
"dependencies": [
288295
"radix-ui"
289296
],
290-
"registryDependencies": []
297+
"registryDependencies": [],
298+
"localEdits": "Forwards `aria-label` to `SliderPrimitive.Thumb`. Upstream renders the Thumb with only a className, so the accessible name never reaches the element screen readers focus."
291299
},
292300
"sonner": {
293301
"source": "https://ui.shadcn.com/r/styles/default/sonner.json",
@@ -308,7 +316,8 @@
308316
"table": {
309317
"source": "https://ui.shadcn.com/r/styles/default/table.json",
310318
"dependencies": [],
311-
"registryDependencies": []
319+
"registryDependencies": [],
320+
"localEdits": "Adds `containerClassName` to override the scroll-wrapper `<div>`. The wrapper is its own `overflow-auto` container by default; inside an already-bounded scroll region (DataTable’s `flex-1 min-h-0 overflow-auto`) that creates a SECOND, height-unbounded scroll container whose horizontal scrollbar sits below every row, reachable only after scrolling to the last one. `containerClassName=\"overflow-visible\"` hands both axes to the outer container. Rationale is spelled out in the file’s JSDoc."
312321
},
313322
"tabs": {
314323
"source": "https://ui.shadcn.com/r/styles/default/tabs.json",

scripts/shadcn-sync.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,12 @@ async function checkComponent(name, manifest) {
256256
// `--update` refuses these; the local lines would be deleted.
257257
status = 'modified';
258258
message = `${localOnly.length} local line(s) upstream lacks — --update would refuse`;
259-
if (upstreamOnly.length > 0) message += `, ${upstreamOnly.length} upstream line(s) pending`;
259+
// Deliberately NOT "N updates available". Both counts are set
260+
// differences, so a line we edited locally appears on both sides: once
261+
// as ours, once as the upstream original it replaced. For a modified
262+
// component this number is mostly the mirror image of its own local
263+
// edits, not new upstream work waiting to be collected.
264+
if (upstreamOnly.length > 0) message += `, ${upstreamOnly.length} not matching upstream verbatim`;
260265
// Divergence with a recorded reason is a decision; divergence without
261266
// one is an open question. Surfacing the split makes the untriaged
262267
// components a visible to-do instead of undifferentiated noise.

0 commit comments

Comments
 (0)