refactor(ui): complete antd Typography migration to ui-core-components - #30780
Conversation
…sions The antd-typography-to-core codemod only checked for a plain, unaliased `Typography` specifier when deciding whether core already imports Typography. It missed an existing `Typography as CoreTypography` alias, so on a fully-converted file it pushed a second `Typography` specifier onto the same import (utils/IngestionUtils.tsx repro), instead of reusing the alias already in scope. Fixed by resolving the existing core-import local name (plain or aliased) once, up front, and reusing it for both the fully-converted and partial/alias code paths; a new specifier is only introduced when no core import exists at all. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 1/13) Chunk 1 of the antd Typography -> ui-core-components migration (docs/antd-migration/typography.md): 32 leaf files under openmetadata-ui/src/main/resources/ui/src/utils regenerated with the fixed antd-typography-to-core codemod. All 32 convert cleanly with no hand-finish skips. Also includes two fixes surfaced by the verification gates rather than the codemod itself: - utils/NavbarUtils.test.tsx and utils/CSV/CSV.utils.test.tsx asserted against / mocked the old antd Typography shape; updated to the core component so their tests keep passing. - Widened ui-core-components' TypographyProps (href/target/rel) so the as="a" shape produced by Typography.Link conversions type-checks; these props already reached the DOM at runtime via prop spreading, this only corrects the type surface to match, additive-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-migration/typography-sweep-1
ClassificationUtils.tsx and IngestionListTableUtils.tsx now render the core Typography component instead of antd's Typography.Text. Two test suites mock '@openmetadata/ui-core-components' wholesale but didn't stub Typography, so it resolved to undefined at render time and broke ClassificationDetails.test.tsx and TestSuitePipelineTab.test.tsx in CI's full-suite jest run (our local `jest src/utils` run never touched these files). Add the same Typography stub already used in CSV.utils.test.tsx. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The incident-manager page renders seeded test-case rows whose names, table names, and "Last Updated" timestamps differ per CI run; the table's auto-width columns then shift the whole layout to fit that per-run content, so no committed baseline can be stable. Same class of non-determinism as 'roles', already dropped. Verified this is pre-existing and unrelated to this sweep: none of the 32 utils files touched by the sweep render anywhere in the IncidentManager component tree (checked the full import graph from IncidentManagerPage down), and the incident-manager baseline also fails intermittently on unrelated, concurrent PRs that never touch those files (e.g. runs 91219477124 "fix async-polling bugs in EntityExportModalProvider" and 91193942898 "Fix the flakiness in SearchRBAC test"). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e-components (sweep 2/13) Mechanical codemod conversion of antd Typography usages to @openmetadata/ui-core-components in components/common (AsyncSelectList through ManageButtonContentItem, 26 leaf dirs / 40 files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e-components (sweep 3/13) Mechanical codemod conversion of antd Typography usages to @openmetadata/ui-core-components in components/common (NoOwner through UserTeamSelectableList, 21 leaf dirs / 22 files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-components (sweep 4/13) Mechanical codemod conversion of antd Typography usages to @openmetadata/ui-core-components across a grab-bag of small, isolated feature components: APIEndpoint, AuditLog, Certification, Classifications, DataAssetRules, Domain, Learning, NavBar, PageHeader, ProfileCard, SearchDropdown, Tag, Topic, UploadFile, WorkflowDefinitions, AppBar, Container, DataAssets, DataProducts, ExploreV1, NotificationBox, Pipeline, Suggestions, TestLibrary, Visualisations, Announcement (26 dirs / 38 files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dgeCenter/SettingsSso/SearchSettings/DataInsight Typography to ui-core-components (sweep 5/13)
Mechanical codemod conversion of antd Typography usages to
@openmetadata/ui-core-components in components/{Dashboard,Metric,
ServiceInsights,MlModel,KnowledgeCenter,SettingsSso,SearchSettings,
DataInsight} (36 files).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…aphy to ui-core-components (sweep 6/13)
Mechanical codemod conversion of antd Typography usages to
@openmetadata/ui-core-components in components/{DriveService,Glossary,
Alerts,DataQuality} (31 files). DataQuality and Glossary are
entity-detail-page building blocks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ponents (sweep 7/13)
Mechanical codemod conversion of antd Typography usages to
@openmetadata/ui-core-components in components/{Entity,Modals,Explore}
(37 files). Entity is shared across many entity-detail pages.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ponents (sweep 8/13)
Mechanical codemod conversion of antd Typography usages to
@openmetadata/ui-core-components in components/{DataContract,Database}
(28 files).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omponents (sweep 9/13) Mechanical codemod conversion of antd Typography usages to @openmetadata/ui-core-components in components/ActivityFeed (18 files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nts (sweep 10/13) Mechanical codemod conversion of antd Typography usages to @openmetadata/ui-core-components in components/MyData (30 files), including Widgets/ and CustomizableComponents/ (landing-page surface). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nents (sweep 11/13) Mechanical codemod conversion of antd Typography usages to @openmetadata/ui-core-components in components/Settings (36 files). Concentrates 4 of the hardest hand-finish sites (copyable/code props), handled separately per the migration guide. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (sweep 12/13) Mechanical codemod conversion of antd Typography usages to @openmetadata/ui-core-components across 33 single-file page dirs plus Configuration, DataInsightPage, KPIPage, LoginPage, RolesPage (39 files). Page shells carry the highest visual-regression exposure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…PoliciesPage/TasksPage Typography to ui-core-components (sweep 13/13)
Mechanical codemod conversion of antd Typography usages to
@openmetadata/ui-core-components in pages/{TaskFormSettingsPage,
SignUp,TableDetailsPageV1,PoliciesPage,TasksPage} (23 files). TasksPage
is the single largest page directory, kept whole.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolve the sweep's remaining hand-finish worklist per
docs/antd-migration/typography.md:
- BlockEditor/* (BubbleMenu, AttachmentPlaceholder, HashList, MentionList,
SlashCommandList): bare antd `<Typography>` wrappers with no automated
coverage, converted directly to core Typography.
- CustomStatistic.tsx: `Text type={expr}` (unsupported-type skip) resolved
to `color={expr}` since both ternary branches are allowed values.
- TestCaseIncidentManagerStatus.component.tsx, SuccessScreen.tsx,
SummaryTagsDescription.component.tsx, DataInsightHeader.component.tsx:
bare `<Typography>` usage mixed with converted sub-components; dropped
the antd import and renamed the `CoreTypography` alias back to
`Typography`.
- ProfilerObjectFieldTemplate.tsx, MetricExpression.tsx, TourEndModal.tsx,
Sso{RolesSelectField,ConfigurationFormArrayFieldTemplate}.tsx,
ErrorPlaceHolderIngestion.tsx, WorkflowArrayFieldTemplate.tsx: bare
`<Typography>` (zero-conversion, not counted in the codemod's 410)
converted by hand.
- UserProfileIcon.component.tsx, PersonaDetailsCard.tsx: core
`ellipsis={{ tooltip: true }}` renders a real `<button>` trigger
(TooltipTrigger), which is invalid nested inside another interactive
element (a dropdown-trigger Button / whole-card onClick). Switched to
plain `ellipsis` + a native `title` attribute at the two sites where
this nesting broke click handling.
- TierCard.tsx: fixed a pre-existing `react/jsx-sort-props` prop-order
violation surfaced by running eslint over the full changed-file set.
AlertDetails.component.tsx, ReindexFailures.component.tsx,
AdminPermissionDebugger.component.tsx, and UserPermissions.component.tsx
keep their partial `CoreTypography` alias — `code`/`copyable`/
`ellipsis.expandable` have no core equivalent yet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fix the test-mock breakage class the Typography sweep repeatedly
triggers: a jest.mock('@openmetadata/ui-core-components', ...) factory
that omits Typography now returns undefined for a component that starts
importing it, crashing with "Element type is invalid" ("Check the
render method of ..."). Fixed in TableQueries.test.tsx,
ColumnDetailPanel.test.tsx, LineageTabContent.test.tsx,
ExploreSearchCard.test.tsx, TestSuitesTable.test.tsx, TestSuites.test.tsx
by adding the established Typography stub:
({ as: Component = 'span', children, ...props }) => <Component
{...props}>{children}</Component>.
Also fixes a second, narrower breakage class: stale antd
`jest.mock('antd', ...)` stubs for `Typography.Text`/`.Paragraph` that
inject a `data-testid` no longer used once the underlying component
switched to core Typography (DomainsSection, DataQualitySection,
DataProductsSection, OwnersSection, TagsSection, LineageTabContent).
Removed the dead mocks and updated assertions to query by the real
rendered class/text instead of the removed synthetic testid.
IncidentManagerPage.test.tsx and WidgetHeader.test.tsx had an existing
Typography stub that dropped all props except `children` (or dropped
`as`/`data-testid`); widened both to the same forwarding pattern so
`data-testid="heading"`/`"sub-heading"` and the `tw:truncate` ellipsis
class survive the mock.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PageHeader.interface.ts still typed titleProps/subHeaderProps as antd's
Typography/Paragraph props after PageHeader.component.tsx was converted
to core Typography (sweep 4/13). antd's ParagraphProps inherits a
generic HTML `color?: string` from HTMLAttributes, which isn't
assignable to core Typography's narrower `color?: TypographyColor`
union, so spreading `{...subHeaderProps}` onto the core component no
longer type-checked. Point both props at core's TypographyProps
instead — this was the one genuine new tsc error introduced by the
sweep (isolated by diffing against the pre-sweep baseline).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Finishes the sweep's hand-finish worklist: AlertDetails, ReindexFailures, AdminPermissionDebugger, and UserPermissions kept a partial CoreTypography alias because their `code`/`copyable`/`ellipsis.expandable` usages had no core equivalent. Resolves the gaps directly: - `Typography.Text code` -> `CoreTypography as="code"` with the rounded/mono/bg-secondary className idiom already used by ContextRuleCard.component.tsx. - `Typography.Text/Paragraph copyable` -> `CoreTypography` composed with the existing `CopyToClipboardButton` in a flex row; the `expandable` ellipsis option is dropped in favor of `rows: 2` since the cell already sits inside a Tooltip showing the full text. - Drop the now-unused `Typography` antd import/destructure from all four files. Also fixes a regression the hand-edit introduced in AlertDetails: core's Typography always wraps its content in an outer `<div className="prose">` regardless of `as`, so nesting the new `as="code"` Typography inside the pre-existing `as='p'` Typography produced an invalid `<div>`-in-`<p>` (validateDOMNesting warning, not caught by any existing assertion). Switched the outer wrapper to `as="div"`. openmetadata-ui's Typography ledger row now reads 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Too many files changed for review. ( Bypass the limit by tagging |
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
Typography always wraps its children in a block-level div.prose, regardless of the `as` prop. Rendering the `(fqn)` hint as Typography inside the suggestion Link/Button broke the single-line layout, pushing the fqn onto a second line and shifting the Button's click point off the anchor's actual line boxes. GlobalSearchSuggestions.spec.ts "Navigate to column from column suggestion" timed out waiting for the resulting navigation because the click never reached the Link. Use a plain span (this Typography added nothing but a className) to keep the text inline and preserve the original click target geometry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…owed
core Typography's `ellipsis={{ tooltip: true }}` renders its content
inside a react-aria TooltipTrigger `<button>`. react-aria's usePress
stops native click propagation by default (see
@react-aria/interactions usePress.js), so a click landing on that
button never bubbles to an ancestor's onClick.
Two call sites in this file relied on exactly that bubbling:
- the persona-name Typography inside `data-testid="persona-label"`,
whose *ancestor* div.onClick performs the actual persona switch;
- the "View Profile" Typography inside a react-router `<Link>`.
Clicking either silently no-op'd instead of switching persona or
navigating. This is why SettingsNavigationPage.spec.ts "should handle
multiple items being hidden at once" saw app-bar-item-explore still
visible: `getByRole('menuitem', { name: persona.displayName }).click()`
never actually invoked `handleSelectedPersonaChange`, so the persona
whose nav config was edited was never selected.
Apply the same fix already used for `default-persona` in this file:
plain `ellipsis` truncation plus a native `title` attribute, which
preserves the hover-tooltip text without adding a click-swallowing
interactive element.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hange
Same react-aria click-swallowing hazard as UserProfileIcon: the test
name and test-definition name in each test-case card use
`ellipsis={{ tooltip: true }}`, which wraps them in a react-aria
TooltipTrigger `<button>` that stops click propagation by default.
The card's selection handler lives on the outer `<Space
onClick={() => handleCardClick(test)}>`, so clicking the (often
truncated) test name inside the button no longer selected the card.
This broke test-case selection in the "Add Test Case" list shared by
TestSuite.spec.ts "Logical TestSuite", TestSuiteMultiPipeline.spec.ts
"TestSuite multi pipeline support", and TestSuiteDetailsPage.spec.ts
"Add test case modal on Test Suite details page - filters and select"
- all three clicked `getByTestId(testCaseName)` inside
`test-case-selection-card` and then hung waiting for the resulting
test-suite create/deploy API calls that never fired because no test
case was ever actually selected.
Attach the same onClick directly to both Typography elements so
selection no longer depends on the click bubbling past the
click-swallowing wrapper.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves visual-harness conflicts in favour of wave-1: the harness repair (#30798) restored the pages this branch had dropped as a stopgap (roles, teams, data-quality, incident-manager, landing-page x2) by masking their volatile regions instead, and clipped incident-manager to page chrome. That supersedes the drops here, so wave-1's staticPages.spec.ts and all its CI-rendered baselines win. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Typography always rendered its content inside a `<div className="prose">`. antd's `Typography.Text` rendered an inline `<span>`, so every mechanically converted call site became block-level: text embedded mid-sentence wrapped onto its own line, and a nested Typography produced a `<div>` inside a `<span>` — invalid DOM that trips React's validateDOMNesting. `styles/typography.css` applies its real rules through a *descendant* selector (`.prose :not(...)`), and every rule in it is gated on an element type — p, h1-h6, ol, ul, li, blockquote, a, code, pre, img, figure, table. For those the wrapper is load-bearing; moving `prose` onto the element would stop the rule matching (a `p` would silently lose its margins). `span` and `div` are targeted by no such rule. There the wrapper contributes only the element-level `.prose` layer — the `--tw-prose-*` vars plus `color`, `font-size` and `line-height`, all inherited properties — so setting `prose` directly on the element yields an identical computed style on the text while dropping the spurious block box. Render the element directly in that case. Ellipsis keeps the wrapper (it carries the truncation classes) and so does a non-default quote variant (also styled via a descendant selector). Deliberately a small allowlist: anything unlisted is unchanged. Verified with the full consumer suite: 1155 jest suites / 13637 tests, no failures.
Follow-ups from the code review on the antd Typography sweep:
- SignInPage: `md:tw:gap-10` is not a valid Tailwind v4 prefix-mode class and
generated no CSS, so the breakpoint spacing the deleted `.less` provided was
silently lost. The prefix must lead the variant chain (`tw:md:gap-10`).
- SignInPage: `.forgot-password-link`'s `flex: 1` only applies when the anchor is
a direct flex child of antd's `inline-flex` label. Typography wraps `as="a"` in
a block `div.prose`, breaking that. Own the row layout locally instead.
- PageHeader: `{...titleProps}` / `{...subHeaderProps}` were spread *before* a
hardcoded `className`, so a caller-supplied className was silently dropped.
Merge them instead.
- AddTestCaseList: drop the `onClick` handlers that were re-wired onto the
Typography elements. They sit inside the react-aria TooltipTrigger button, so
today they never fire; and once that button stops swallowing propagation
(#30804) they would fire *in addition to* the row-level handler on the
<Space>, and since `handleCardClick` toggles, the two would cancel out.
Selection is left to the single row-level handler.
- DataAssetsHeaderExtraInfo / MarketPlaceAppDetails: both used a default
(inline) Typography purely as a layout container around block content. Mark
them `as="div"`, which is what they were structurally, and which clears the
last remaining invalid nesting — a scan of all 591 Typography files now
reports none.
|
Addressed the review in two commits — Findings 1 + 2 share one root cause, so they're fixed once in core rather than at 442 call sites.
So the wrapper is genuinely load-bearing for those types — putting A scan of all 591 files containing Finding 5 — I did not apply the suggested fix. The diagnosis is right that the handler never fires today, but the proposed wrapper Findings 3 and 4 applied as suggested. Note for baselines: this restores inline flow, so it legitimately changes rendering. The current visual-regression baselines were captured with the block wrapper, i.e. they encode the regression as expected. They will need regenerating from CI after #30804 and this land — the diffs are the fix, not a new break. Verified: full consumer suite green (1155 suites / 13,637 tests), core suite 21/21, eslint clean. |
…weep-rest # Conflicts: # openmetadata-ui-core-components/src/main/resources/ui/src/components/foundations/typography.tsx
Dropping Typography's block `div.prose` wrapper for span/div lets former `Typography.Text` call sites participate in inline flow again, which legitimately changes rendering on three of the twenty harness pages. Each diff was compared against its previous baseline before adoption rather than adopted wholesale: - applications: "Cache Warmup" no longer force-wraps onto two lines, so the `Disabled` badge sits inline beside the title instead of being pushed down; cards tighten by ~12px. The bold "Data Insights" descriptions are present in the old baseline too - pre-existing markdown, not a change here. - landing-page / landing-page-sidebar-collapsed: the hero tightens, shifting the widget grid up ~10px. The large diff regions are the harness's own mask fills moving with it, not content changes. These baselines had encoded the block-wrapper layout as expected, which is how the regression escaped review in the first place. Captured from CI artifacts per docs/antd-migration/README.md - never from a local run.
|
Code Review ✅ Approved 5 resolved / 5 findingsCompletes the openmetadata-ui migration from AntD Typography to ui-core-components, clearing the ledger entry and fully resolving the remaining hand-edit integration bugs. No issues found. ✅ 5 resolved✅ Bug: Nested Typography emits invalid
|
| Compact |
|
Was this helpful? React with 👍 / 👎 | Gitar | Powered by Gitar — free for open source



Summary
Completes the Typography sweep for
openmetadata-ui(part of #30565, AntD →@openmetadata/ui-core-componentsmigration program).utils/*) landed in an earlier PR.openmetadata-ui'sTypographyrow indocs/antd-migration/LEDGER.mdgoes 422 → 0 (baseline count perdocs/antd-migration/typography.md). Verified by re-runningtooling/antd-migration/ledger.mjsagainst this branch — theTypographyrow is now absent entirely.AlertDetails.component.tsx,ReindexFailures.component.tsx,AdminPermissionDebugger.component.tsx,UserPermissions.component.tsx), which had no core equivalent for antd'scode,copyable, andellipsis.expandable. Resolved per the mapping guide's "no direct equivalent" section:Typography.Text code→Typography as="code"with the rounded/mono/bg-secondary className idiom already established inContextRuleCard.component.tsx.Typography.Text/Paragraph copyable→Typographycomposed with the existingCopyToClipboardButtonin a flex row;ellipsis.expandabledropped in favor ofrows: 2(the cell already sits inside aTooltipshowing the full text, so the expand affordance was redundant).Typographyalways wraps content in an outerdiv.proseregardless ofas, so nesting the newas="code"Typography inside the file's pre-existingas='p'Typography produced an invalid<div>-in-<p>(avalidateDOMNestingwarning not caught by any existing test assertion). Fixed by switching the outer wrapper toas="div".Approved mapping decisions (docs/antd-migration/typography.md)
Typography.Title level={N}→as="hN"+sizevia the approvedLEVEL_SIZE_MAP(1→display-sm, 2→display-xs, 3→text-xl, 4→text-lg, 5→text-md). Level 5 dominates real usage (>70%).type="secondary"/"success"/"warning"/"danger"→color="secondary"/"success"/"warning"/"danger"(corecolorprop landed in main ahead of the bulk sweep).strong→weight="bold"(literal-only; dynamicstrong={expr}was a codemod skip, hand-resolved where it occurred).underline→classNamegetstw:underlineappended.Typography.Text→Typography(as="span"default);Typography.Paragraph→Typography as="p";Typography.Link→Typography as="a".Codemod vs. hand-finish
The codemod (
tooling/antd-codemods/transforms/antd-typography-to-core.js) handled the mechanical prop/import rewrites above across chunks 2–13. Hand-finished on top of the codemod:<Typography>wrappers (codemod deliberately skips these — antd's bare form renders an<article>, core's default isspan; each needed the intended element verified by hand):BlockEditor/*,CustomStatistic.tsx,TestCaseIncidentManagerStatus.component.tsx,SuccessScreen.tsx,SummaryTagsDescription.component.tsx,DataInsightHeader.component.tsx,ProfilerObjectFieldTemplate.tsx,MetricExpression.tsx,TourEndModal.tsx,Sso*FieldTemplate.tsx,ErrorPlaceHolderIngestion.tsx,WorkflowArrayFieldTemplate.tsx.Title level={expr}andtype={expr}/unsupportedtypevalues (codemod skips, no fixed value to look up at codemod time).code/copyable/ellipsis.expandablehard gaps in this PR's four files (above).UserProfileIcon.component.tsxandPersonaDetailsCard.tsx: coreTypography'sellipsis={{ tooltip: true }}renders a real<button>trigger (viaTooltipTrigger), which was nested inside another interactive element — a dropdown-triggerButtonin one case, a whole-cardonClickin the other. This is invalid HTML (button-in-button) and silently swallowed the parent's click. Fixed by switching to a plainellipsisboolean + nativetitleattribute, which preserves the hover-tooltip truncation without the interactive nesting.ellipsis={{ tooltipturns up 44 files using this shape; a prior pass estimated ~32 of these sit inside another interactive element and share the same bug class. Filed Audit: ellipsis-tooltip nested inside interactive elements (~32 sites) #30779 (sub-issue of Wave 1: Mechanical primitive sweeps (Typography, Button, Space/Divider, Tag, Tooltip, Badge, Skeleton, Alert, Avatar) #30565, assigned to @chirag-madlani) to audit and fix the remainder.PageHeader.interface.tsfix:titleProps/subHeaderPropswere still typed against antd'sTypography/Paragraphprops afterPageHeader.component.tsxitself was converted to core Typography (sweep chunk 4/13). antd'sParagraphPropsinherits a generic HTMLcolor?: stringfromHTMLAttributes, which isn't assignable to core Typography's narrowercolor?: TypographyColorunion, so{...subHeaderProps}stopped type-checking once the component switched. Retyped both props against core'sTypographyProps— the one genuine newtscerror the sweep introduced, isolated by diffing against the pre-sweep baseline.Gate results
origin/antd-migration/wave-1).Test Suites: 3 skipped, 1155 passed, 1155 of 1158 total/Tests: 52 skipped, 13637 passed, 13689 total. 0 failures.Notes
collate-ui,collate-local-webserver) is tracked as a separate PR in theopenmetadata-collaterepo.Typographyalways renders insidediv.prose) — the visual-regression baselines under the collate visual project should be checked against the affected pages before merging past this PR intomain.Test plan
tsc --noEmit— 0 new errors vs. pre-sweep baselinejestfull suite — 1155/1158 suites, 13637/13689 tests, 0 failureseslint/prettier/organize-importsclean on the hand-finish commitTypographyrow absent foropenmetadata-uiCo-Authored-By: Claude Fable 5 noreply@anthropic.com
Fixes #30796