Skip to content

fix(docsite): render the component anatomy table - #4847

Merged
cixzhang merged 3 commits into
facebook:mainfrom
AKnassa:rocky/docsite-anatomy-render
Aug 24, 2026
Merged

fix(docsite): render the component anatomy table#4847
cixzhang merged 3 commits into
facebook:mainfrom
AKnassa:rocky/docsite-anatomy-render

Conversation

@AKnassa

@AKnassa AKnassa commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

What this does

Component pages on the doc site now show an Anatomy table — the named parts a
component is made of, and what each one is for. Avatar, for example, now lists Photo,
Initials, Default icon, and Status dot.

Why

That information was already written down and already reaching the page — 55 components
describe their anatomy, 236 parts in total. The table that displays it had been built too.
It just was never connected to anything, so the doc site quietly showed none of it while
the CLI (astryx component <Name>) showed it all.

So this isn't new content or a new feature. It's switching on writing that authors have
been doing all along.

What changed

anatomy-avatar anatomy-avatargroup-required
  • The component Overview tab now renders the Anatomy table when a component describes
    its parts, and shows nothing when it doesn't.
  • Anatomy sits above Best practices, the same order the CLI already uses.
  • The Anatomy heading now matches the size of the headings around it (Usage, Best
    practices). It had been set smaller.
  • A new test fails if any piece of the component-detail page ever becomes disconnected
    again, which is the exact way this was missed.

No changes to any published package, and no change to what authors write.

For reviewers: how it was never noticed

Anatomy.tsx arrived with the doc site in f45f465 and was never imported —
git log -S "Anatomy" on ComponentDetailClient.tsx returns nothing, so it was never
wired rather than deliberately unwired. The data path was always intact:
generate-data.mjs forwards the whole usage block, and the emitted registry type
declares anatomy.

The new test resolves import specifiers the way the bundler does, so a package path like
@astryxdesign/core/Section can't be mistaken for a local file. It's scoped to
component-detail/ on purpose — that folder holds only internal building blocks, with no
route entry points and no script-consumed modules, so an unimported file there is always
a bug.

Two notes on scope. ThemeShowcaseTile.tsx is a second orphan from the same commit; it's
left alone because where it belongs on /themes is a design question, not a wiring bug.
And the docsite typecheck reports one pre-existing error in the generated registry
(DerivedVar."replaces") — verified identical with these changes reverted.

How to see it

pnpm build
pnpm -F @astryxdesign/docsite dev

Tests: pnpm -F @astryxdesign/docsite test — 21 files, 326 tests.

Anatomy.tsx has existed since the doc site landed (f45f465) but nothing
ever imported it -- `git log -S Anatomy` on ComponentDetailClient.tsx is
empty, so it was never wired rather than deliberately unwired. Meanwhile 55
component entries carry `usage.anatomy` (236 elements, 97 of them required):
generate-data.mjs passes the whole `usage` block through, and the emitted
registry type declares the field. The data reached the page and had nowhere
to go, so the docsite silently showed nothing while the CLI rendered the
same data at clients/cli/lib/component-format.mjs:207.

Wire Anatomy into the Overview tab, placed before Best practices to match
the CLI's section order, and align its heading with its peer section
(level 2 / display-3, gap 4) instead of a bare level-3.

Add a wiring test that fails if any module under component-detail/ becomes
unreachable from an import, resolving specifiers the way the bundler does so
a package path like `@astryxdesign/core/Section` cannot be mistaken for a
local file. That directory holds only internal building blocks -- no route
entry points, no script-consumed modules -- so an orphan there is always a
bug. A second test guards the generator against dropping `anatomy` from the
`usage` block it forwards.

No issue filed; found while triaging an unrelated documentation RFC.
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

@AKnassa is attempting to deploy a commit to the Meta Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 9, 2026
@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge needs:design-review Affects visuals — Design should review labels Aug 9, 2026
@AKnassa
AKnassa marked this pull request as ready for review August 9, 2026 23:56

@kentonquatman kentonquatman 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.

Please wrap the table in a card so that it matches the styling of all other tables on this page. The "required" badge also seems oddly positioned in the screenshot. Please update so that it's an inline bold text element as part of the description (eg. "Required: Avatar elements that from...").

Review feedback on facebook#4847.

The anatomy table rendered bare while the tables around it sit in cards.
BestPracticesBlock -- directly below it in the same Usage block -- wraps
its Table in `<Card variant="default">`, and the /docs TableBlock does
the same. Match them.

The required flag lived in its own 80px column under an empty header, so
the badge floated in a gap between Element and Description. Fold it into
the description as a bold `**Required:**` lead-in instead, which also
retires an empty table header. This mirrors how the CLI marks its
guidance rows (`**Do:**` / `**Don't:**` in component-format.mjs), so a
required part reads the same way in both surfaces.

The shaping lives in anatomyHelpers.ts, following the themingHelpers.ts
split, so the lead-in logic is unit-testable without rendering React.
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Error Error Aug 24, 2026 3:02am

Request Review

@cixzhang cixzhang 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.

Thanks — both of Kenton's asks are in; approve. Description still shows the badge column. Red Vercel looks like the DerivedVar error you flagged, since fixed on main — try a merge.

[Reviewed by Robohands]

// Guard against a vacuous pass if the directory is ever moved or renamed.
expect(detailModules.length).toBeGreaterThan(5);

const imported = collectImportedFiles(walk(SRC_DIR));

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.

A unit test on an orphan silences this. Might need the .test. filter from :83.

{
key: 'name',
header: 'Element',
width: pixel(140),

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.

140 hard-breaks Optional/Requ ired indicator on the Field page. Might need a little more width.

@github-actions github-actions Bot removed the needs:code-review High-risk change (new package/component/API) — needs human code review before merge label Aug 24, 2026
@cixzhang
cixzhang dismissed kentonquatman’s stale review August 24, 2026 02:50

Both asks are in at f055409 — the table is wrapped in Card variant="default" matching BestPracticesBlock, and required is now a bold **Required:** lead-in inside the description rather than a badge column. Dismissing so this can land; reopen if the rendering is not what you meant.

@cixzhang
cixzhang merged commit 78e8e1c into facebook:main Aug 24, 2026
17 of 18 checks passed
@cixzhang

Copy link
Copy Markdown
Contributor

Merged — I merged main into your branch myself rather than sending it back to you, since the staleness was our latency, not anything wrong with your work. Thank you, @AKnassa, for wiring up the Anatomy renderer the system already had and never actually rendered: 64 component pages now show their parts instead of hiding them, with Required: reading inline the way Kenton asked. I'm sorry this sat for two weeks before we got to it.

[Reviewed by Robohands]

cixzhang added a commit that referenced this pull request Aug 24, 2026
…id-word

Two defects the #4847 review surfaced, both ours.

The component-detail wiring guard collected importers by walking all of
src/, so a renderer imported only by its own unit test counted as wired.
Unwire Anatomy and add a test that imports it and the guard goes green
while the section ships dark — exactly what it exists to prevent. Walk
the import graph out from app/ instead: reachability from the router,
not "somebody imports it". That also closes the case the .test. filter
would have left open — a module reached only by other modules the page
never reaches.

The Anatomy table lays out fixed at pixel(140), leaving ~108px of
content box. "Optional/Required" (Field) and "Collapse/expand" (SideNav)
are wider than that and a solidus is not a break opportunity in CSS the
way a hyphen is, so Chromium breaks them inside a word instead:
"Optional/Requ / ired indicator". Offer the break the text implies with
a <wbr /> after each solidus. Nothing moves: the column stays 140px on
every component page.
cixzhang added a commit that referenced this pull request Aug 24, 2026
…id-word (#5391)

Two defects the #4847 review surfaced, both ours.

The component-detail wiring guard collected importers by walking all of
src/, so a renderer imported only by its own unit test counted as wired.
Unwire Anatomy and add a test that imports it and the guard goes green
while the section ships dark — exactly what it exists to prevent. Walk
the import graph out from app/ instead: reachability from the router,
not "somebody imports it". That also closes the case the .test. filter
would have left open — a module reached only by other modules the page
never reaches.

The Anatomy table lays out fixed at pixel(140), leaving ~108px of
content box. "Optional/Required" (Field) and "Collapse/expand" (SideNav)
are wider than that and a solidus is not a break opportunity in CSS the
way a hyphen is, so Chromium breaks them inside a word instead:
"Optional/Requ / ired indicator". Offer the break the text implies with
a <wbr /> after each solidus. Nothing moves: the column stays 140px on
every component page.
@github-actions
github-actions Bot deleted the rocky/docsite-anatomy-render branch August 24, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team) needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants