Repository navigation
fix: zero-config examples, and React Aria starters in an app's src/components - #257
Merged
Merged
Conversation
…mponents The shadcn demo shipped an onsystem.config.json only because its docs sat outside docs/components/, so it did not show the zero config the README promises. It now has a components.json and its docs in docs/components/; check finds the same 11 problems. Add a Tailwind v3 shadcn/ui example (HSL channel tokens, tailwind.config.ts) and a React Aria Components example whose components sit in src/components/ next to App.tsx, and typecheck every example in CI. Zero config now reads a flat folder of components that wrap a primitives library in src/components/, components/ or app/components/, with the same guard as a flat src/ (five PascalCase files, four in five importing the library). Before, React Aria's starter copied into an app gave "No design-system components found". Also: the demo README's problem count, shadcn/ui's MIT notice next to the components adapted from it, and a .gitignore in each example.
- PRIMITIVES (src/detect.ts and the hook's copy) leaves out @radix-ui/react-icons: five of an app's own components that each show a Radix icon were taken for a design system, and check skipped them. A test keeps the hook's copy the same as src/detect.ts's. - inspect --explain names the primitives libraries, not the first one, when a package depends on more than one. - examples/react-aria says its components are adapted from React Aria's Tailwind starter, ships the starter's Apache-2.0 license as LICENSE-react-aria, and says the zero-config detection needs onsystem 0.11.1 or later.
Apache-2.0 asks a modified file to carry a notice that it was changed: each file under examples/react-aria/src/components now names the starter and LICENSE-react-aria. inspect --explain also keeps its old wording when no primitives dependency is listed.
Merged
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.
Roadmap item: OS2-57 (examples: zero-config demo, Tailwind v3 and React Aria examples, typecheck in CI). Part of #216.
What was wrong
examples/shadcn-demohad nocomponents.jsonand shipped anonsystem.config.json. The config only existed because the docs sat indocs/*.md, outside the defaultdocs/components/**. Without it,inspectprintedfiles 5 component files, 1 token file, 0 docs.src/components/next toApp.tsx, and the flat-folder rule only looked at a top-levelsrc/with no app entry. On main, with the newexamples/react-aria:inspectprintedfiles 0 component files,check .checked the components as app code and said "No design-system components found: the component rules did not run", andinit --yesstopped with "zero config found no design system".danger-zone.tsxgets "one problem per rule";checkreports 11 problems across the 8 rules (no-hardcoded-color3,no-hardcoded-spacing2). The components adapted from shadcn/ui did not carry shadcn/ui's MIT notice. The examples'typechecknever ran in CI (the root tsconfig excludesexamples). No example had a.gitignore.What changed
examples/shadcn-demo: a new-yorkcomponents.json, the docs moved todocs/components/,onsystem.config.jsonremoved.inspectnow printsconfig (defaults)anddetected components.json (ui: @/components/ui → components/ui)with5 docs.check "app/**/*.tsx"output is byte-identical to main's (8 errors, 3 warnings). The README table listscomponents.json, says "checkreports 11 problems, at least one for each of onsystem's 8 rules", and linksLICENSE-shadcn(shadcn/ui's MIT license, copied as published). Plus a.gitignore.examples/tailwind-v3(new): shadcn/ui as it was on Tailwind v3: bare HSL channel tokens inapp/globals.css, atailwind.config.tsthat maps them to classes,forwardRefcomponents, acomponents.jsonthat names both. No config:inspectfinds it throughcomponents.json.check .reports 9 problems on the draft page; for example,text-[#71717a]matches--muted-foregroundexactly and the fix istext-muted-foreground, a class fromtailwind.config.ts. The README says thatno-hardcoded-spacingdoes not run there, since onsystem takes the spacing scale from a Tailwind v4 stylesheet or spacing tokens (see follow-ups).examples/react-aria(new): an app with React Aria Components insrc/components/next tosrc/App.tsxandsrc/main.tsx, adapted from the React Aria Tailwind starter (tailwind-variants,composeRenderProps, the starter'scomposeTailwindRenderPropsandfocusRing), restyled with Tailwind v4 tokens in@theme. The README says so and linksLICENSE-react-aria, the starter's Apache-2.0 license as react-spectrum publishes it (with itsCopyright 2019 Adobeline).inspectprintsdetected src/components/ (7 components wrapping react-aria-components).check .reports 7 problems on the draft, including<Checkbox> has no prop "checked". Did you mean "isSelected"?and<Switch> has no prop "disabled". Did you mean "isDisabled"?.src/detect.ts: after a flatsrc/, zero config triessrc/components/,components/andapp/components/with the same rule: a primitives dependency, at least five PascalCase.tsx/.jsxfiles at the folder's top level, four in five of which import the library. The app-entry check applies only tosrc/. The defaultcomponents/uiglobs stay in, the app's stylesheets are the theme (the default token globs), andinitwrites the glob it found.inspect --explaingets a line per folder it looked at, and names the primitives libraries when the app depends on more than one (import a primitives library (react-aria-components, @radix-ui/react-dialog)).@radix-ui/react-iconsmatched@radix-ui/react-*, so five of an app's own components that each show a Radix icon were taken for a design system andcheckskipped them.PRIMITIVESnow leaves it out, insrc/detect.tsand in the hook's copy (plugins/onsystem/hooks/check-ui.mjs), which a test keeps the same. No other icon library the repo knows (theICON_SOURCElist insrc/lint/rules/components.ts: lucide, Heroicons, Tabler, Phosphor and the rest) matches the list. This also applies to the flatsrc/rule that main already has.pnpm --filter "./examples/*" typecheckin the "Lint, typecheck, build" job.docs/configuration.md(zero config, rule 4) on the copied-starter layout, and that Radix's icons do not count.The two new examples use the npm release through
npx -y onsystem, like the demo. The React Aria example's README says its zero-config detection needs onsystem 0.11.1 or later (0.11.0 is being released without this change). With main's build,inspecton a copy of it printsfiles 0 component files, 1 token file, 0 docsandcheckends with "No design-system components found: the component rules did not run"; with this branch's,detected src/components/ (7 components wrapping react-aria-components)and 7 problems.Outside the listed files
The plan listed
.github/workflows/ci.yml, the three example folders,src/detect.tsandtest/example.test.ts. These had to change too:pnpm-lock.yaml:examples/*is a pnpm workspace glob, so the two new examples are workspace packages andpnpm install --frozen-lockfileneeds their importers. 38 packages are added, all fromtailwindcss@3.4.19andtailwind-merge@2.6.1for the Tailwind v3 example; the other dependencies reuse versions already in the lockfile.test/extract.test.ts,test/server.test.ts: the demo's Button docs path is nowdocs/components/button.md(one line each).test/config.test.ts: the--configtest used the demo's config file, now the ACME fixture's.test/setup-steps.test.ts: the test of a project that already has a config writes one into its copy of the demo. The finding named these references.docs/configuration.md: one sentence, as the finding proposed.test/detect-components-folder.test.ts.plugins/onsystem/hooks/check-ui.mjs: the same@radix-ui/react-iconsexclusion in its copy ofPRIMITIVES(one line).No open pull request touches these files.
Not in this pull request
app/globals.css(--font-sans: var(--font-geist-sans), which nothing defines). shadcn/ui's Next.js template has the same lines, wherenext/fontsets the variables at run time, andtest/export.test.tsuses them for the unresolved-font case ("Wrote 31 tokens",font-sansasvar(--font-geist-sans)). Dropping or defining them changes those export tests; that belongs in a pull request on the export tests.lucide-react1.59.0 on 2026-10-17,@radix-ui/react-slot1.5.0 on 2026-10-12,@radix-ui/react-dialog1.2.0 on 2026-10-05). Dependabot raises the floors on every update (it did on 2026-10-21), so lowering them here would not last: that needsversioning-strategyfor the examples in.github/dependabot.yml. The new examples start with floors at least four weeks old.no-hardcoded-spacingon Tailwind v3. It does not run on a v3 project, since the default spacing unit is only added for a stylesheet that importstailwindcss. This is the documented behaviour indocs/rules.md; changing it is asrc/tokenschange of its own.base-nova) shadcn app in the corpus. The corpus is frozen after this wave, and adding a repository changes the README's corpus figures./plugins/design-system-mcp; it needs a check of the listing in a browser.plugins/onsystem/hooks/check-ui.mjs) gets the icons fix but still looks only at a flatsrc/, which matters only for a monorepo root that keeps such components in its ownsrc/components/.How it was tested
New tests, which fail on main:
test/example.test.tsnow runs the same checks on every folder inexamples/(a test fails when a folder is added without an entry): the README's first steps work in a copy of the folder made outside the repository with its dependencies linked; there is no onsystem config, andinspectin the copy printsconfig (defaults)and the expecteddetectedline;checkexits 1 on the draft page only, and the README's table gives its exact number of problems; a.gitignorelistsnode_modules; the example hastypecheckand CI runspnpm --filter "./examples/*" typecheck. Per example: the demo covers all 8 rules and reads 5 docs fromdocs/components/; the shadcn-derived examples carryLICENSE-shadcnwith shadcn/ui's copyright line; the Tailwind v3 example matchestext-[#71717a]to--muted-foregroundthroughtailwind.config.ts; the React Aria example suggestsisSelectedandisDisabledfrom React Aria's types. Run against main'sexamples/shadcn-demoandci.yml, the demo's checks fail on the config file, the README's count, the rule-count wording, the missing.gitignoreand the missing CI typecheck.test/detect-components-folder.test.ts: React Aria's starter insrc/components/next tomain.tsxandApp.tsxis detected, with the default globs kept andsrc/index.cssas the theme;inspect --explainsays why;checkon a new page reports a native<button>for<Button>;init --yeswritessrc/components/*.{tsx,jsx};components/andapp/components/in a Next.js app are detected, Radix wrappers too; a folder of the app's own features, fewer than five components, or no primitives dependency is left alone; five of an app's own components incomponents/or a flatsrc/that import only@radix-ui/react-iconsare left alone, andcheckreports their hardcoded color;inspect --explainnames one primitives dependency, or lists them when there are more; the hook'sPRIMITIVESis the same assrc/detect.ts's; a flatsrc/still comes first. The icons and explain tests fail on this branch before this fix.test/example.test.ts: the React Aria example's README says it is adapted from the starter, linksLICENSE-react-aria, and the file has the Apache-2.0 text withCopyright 2019 Adobe.Gate, on the branch merged with main after #255:
pnpm install --frozen-lockfile --prefer-offline,pnpm format:check,pnpm lint,pnpm typecheck,pnpm --filter "./examples/*" typecheck,pnpm test(107 files passed, 1 skipped; 1403 tests passed, 3 skipped),pnpm buildandpnpm smokepass. I also ran CI's two demo steps by hand (check app/settings/members.tsx --format githubexits 0; the hook ondanger-zone.tsxexits 2 withno-unknown-variant), andpnpm --filter site generate,pnpm --filter site test(22 files, 294 tests) andpnpm --filter site typecheck, since the site loads the demo and rendersdocs/configuration.md.Corpus: the detection changes could move counts, so I ran
node scripts/corpus.mjsafter the build, again after the icons fix. It printed "Counts match corpus/snapshot.json" for the 25 runs, and all 80 labels of the blind sample are still reported.node scripts/corpus.mjs eslintprinted "The ESLint plugin reports what check reports in 25 runs." The snapshot is unchanged. I did not run the installed-types corpus (--installed), which CI runs weekly.