fix(ui-core): stop Typography ellipsis tooltip from swallowing ancestor clicks - #30804
Conversation
…or clicks
Typography's ellipsis-tooltip path wraps truncated content in
`TooltipTrigger`, which renders a react-aria `Button`. react-aria's
`usePress` hook stops a completed press from propagating to ancestor DOM
listeners by default - this is documented, intentional behavior
("the default for React Spectrum components is not to propagate. This can
be overridden by calling continuePropagation() on the event", see
@react-types/shared/src/events.d.ts) - not a bug in react-aria itself.
Verified at the source level in node_modules/@react-aria/interactions'
usePress: the returned onClick handler unconditionally calls
`e.stopPropagation()` unless `continuePropagation()` was called on the
PressEvent during onPress/onPressStart/onPressEnd.
For Typography's ellipsis tooltip specifically, that default is wrong: the
wrapper only exists to host a hover/focus tooltip over otherwise
non-interactive text, so any ancestor `onClick` (a selectable card, a
persona-switcher row, ...) should still receive the click. Real breakage
from this in the antd->core Typography migration (PR #30780): the persona
switcher's row onClick never fired, and AddTestCaseList's selectable cards
could not be selected at all, hanging three e2e specs. With ~57
`ellipsis={{ tooltip: ... }}` call sites in openmetadata-ui and only a
handful covered by e2e, an unknown number of click targets were silently
broken.
Fix: pass an `onPress` handler to the ellipsis path's `TooltipTrigger` that
calls `event.continuePropagation()`, restoring default click propagation
for all 57 call sites with no per-site changes needed.
Scoped to Typography's own usage rather than changing `TooltipTrigger`'s
default: grepping other `TooltipTrigger` consumers in this package
(form-item-label, input, table column header, avatar-add-button) found a
case - the sortable table column header's help-icon tooltip - that
actively relies on the click-swallowing default so the help icon doesn't
also trigger the header's sort-on-click. Changing the shared component
would have fixed Typography at the cost of regressing that case.
Added regression tests in typography.test.tsx: click propagates to an
ancestor onClick (fails without the fix), tooltip still shows on hover and
on keyboard focus, and non-ellipsis Typography is unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
✅ PR checks passedThe linked issue has a description and all required Shipping project fields set. Thanks! |
Code Review ✅ ApprovedFixes antd Typography ellipsis tooltip interaction by configuring event propagation so clicks reach ancestor handlers. No issues found. OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar | Powered by Gitar — free for open source |
There was a problem hiding this comment.
Pull request overview
Fixes a UI-core interaction bug where Typography with ellipsis={{ tooltip: ... }} prevented ancestor onClick handlers from firing because the underlying react-aria press handling stops propagation by default.
Changes:
- Allows ellipsis-tooltip presses to propagate by calling
PressEvent.continuePropagation()on theTooltipTriggerused byTypography’s ellipsis-tooltip branch. - Adds regression tests to ensure ancestor clicks work while hover/focus tooltip behavior remains intact.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| openmetadata-ui-core-components/src/main/resources/ui/src/components/foundations/typography.tsx | Opts Typography’s ellipsis-tooltip TooltipTrigger into press propagation to restore ancestor click handlers. |
| openmetadata-ui-core-components/src/main/resources/ui/src/components/foundations/typography.test.tsx | Adds test coverage for click propagation and tooltip behavior on hover and keyboard focus. |
| // `TooltipTrigger` renders a react-aria `Button`, whose `usePress` hook stops | ||
| // a completed press from propagating to ancestor DOM listeners by default | ||
| // (react-aria's documented behavior: "the default for React Spectrum | ||
| // components is not to propagate. This can be overridden by calling | ||
| // continuePropagation() on the event" - see | ||
| // node_modules/@react-types/shared/src/events.d.ts). For most `TooltipTrigger` | ||
| // call sites that is desirable (e.g. a help-icon tooltip nested inside a | ||
| // sortable table header should not also trigger the header's sort-on-click). | ||
| // But Typography's ellipsis tooltip wraps *arbitrary, non-interactive* text | ||
| // content: the wrapper is only there to host the hover/focus tooltip, so a | ||
| // click on the truncated text should reach whatever ancestor `onClick` the | ||
| // consumer attached (e.g. a selectable card, a persona-switcher row). Calling | ||
| // `continuePropagation()` here restores that click, scoped to this call site | ||
| // only - it does not change `TooltipTrigger`'s default for its other | ||
| // consumers (form-item-label, input, table column header, avatar add button). | ||
| const allowEllipsisTooltipPressToPropagate = (e: PressEvent) => { | ||
| e.continuePropagation(); | ||
| }; |
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.
🚦 Removed from the merge queue —
|
#30780) * fix(tooling): reuse existing core Typography import in partial conversions 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> * refactor(ui): migrate utils/* Typography to ui-core-components (sweep 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> * test(ui): fix core-components mocks broken by typography sweep 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> * test(ui): drop non-deterministic incident-manager visual baseline 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> * refactor(ui): migrate components/common (part A) Typography to ui-core-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> * refactor(ui): migrate components/common (part B) Typography to ui-core-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> * refactor(ui): migrate small isolated components Typography to ui-core-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> * refactor(ui): migrate Dashboard/Metric/ServiceInsights/MlModel/KnowledgeCenter/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> * refactor(ui): migrate DriveService/Glossary/Alerts/DataQuality Typography 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> * refactor(ui): migrate Entity/Modals/Explore Typography to ui-core-components (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> * refactor(ui): migrate DataContract/Database Typography to ui-core-components (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> * refactor(ui): migrate components/ActivityFeed Typography to ui-core-components (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> * refactor(ui): migrate components/MyData Typography to ui-core-components (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> * refactor(ui): migrate components/Settings Typography to ui-core-components (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> * refactor(ui): migrate pages (part A) Typography to ui-core-components (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> * refactor(ui): migrate TaskFormSettingsPage/SignUp/TableDetailsPageV1/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> * refactor(ui): hand-finish typography conversions 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> * test(ui): fix core-components mocks for typography sweep 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> * fix(ui): type PageHeader title/sub-header props against core Typography 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> * refactor(ui): migrate final Typography holdouts off antd 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> * fix(ui): keep ExploreTree title testid's parent stable for e2e selectors Core Typography always wraps its children in an extra div.prose, so the element carrying `data-testid="explore-tree-title-*"` is no longer a direct child of the `d-flex justify-between` row — it now sits one level deeper, inside that wrapper div. ExploreBrowse.spec.ts and ExploreTree.spec.ts both walk `getByTestId(...).locator('..')` to reach the sibling `.explore-node-count` badge, and were landing on the prose div instead of the row, so the count badge was never found. Move the testid off Typography onto a plain <span> wrapper at the row's original DOM position, with Typography nested inside it purely for text styling. Restores the DOM shape the e2e specs (and the CSS in explore-tree.less targeting `[data-testid^='explore-tree-title-']`) expect, without reverting the Typography migration. See #30779 for the general div.prose blast-radius writeup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): use a native button for nested-column links to restore e2e/a11y Core Typography always wraps its children in an extra div.prose. The nested-column link (`.nested-column-name`) used to be an antd Typography.Link, rendered directly as <a>, a direct child of the padded <p style="padding-left: {depth*8}px"> row. After the sweep converted it to `<Typography as="a">`, the div.prose wrapper interposed between the <a> and that <p>, so `.nested-column-name.locator('..')` (used by Entity.spec.ts's "Complex nested column structures" e2e test to read `getComputedStyle(el).paddingLeft`) landed on the prose div instead, which has no padding — the indentation assertion always saw `0px`. Typography wasn't buying anything here beyond a plain className, so drop it for a native element at the original DOM position. Used <button> rather than plain <a> (which has no href) — a bare interactive <a> without href also trips 3 jsx-a11y warnings (anchor-is-valid, no-static-element- interactions, click-events-have-key-events) that a real <button> avoids for free. Updated the one test that asserted `closest('a')` to match. See #30779 for the general div.prose blast-radius writeup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(ui): regenerate applications baseline, drop non-deterministic pages playwright-visual-regression failed on 6 static pages in PR #30780's CI run (30667147887). Investigated each by downloading the actual/expected/diff PNGs: - applications (marketplace): ~3% diff, static marketplace-app content (no seeded data). Genuine, minor Typography-driven vertical shift (ApplicationCard's `Typography as="h5" size="text-md"` doesn't reproduce antd Typography.Title level=5's exact metrics). Regenerated the baseline from this run's correct render. - teams, data-quality: baked-in aggregate/seeded content (team names with Playwright-generated random suffixes, Total Users/Teams counts, Data Assets Coverage numbers) that drifts every CI run as other specs create data in the shared environment — same non-determinism class as the already-dropped 'roles'/'incident-manager' entries. No file this sweep touches renders these values. Dropped from PAGES with the same documentation style as the existing precedents. - landing-page (+ its collapsed-sidebar variant): already masked/tolerance- bumped for known async-widget variance, but still saw 9-21% diffs this run — the committed baseline itself was captured mid-load (skeleton rows, empty KPI state), so no single screenshot can be stable against it. Confirmed unrelated to this sweep (LeftSidebar.component.tsx is the only touched file on this page, and only its logout-modal text changed). Dropped both entries. - explore: small (~2%) remaining diff after the existing masks, from an unmasked pagination total and an environment-toggled AI-search icon. Bumped maxDiffPixelRatio to 0.03, matching the tolerance already used for landing-page's known-volatile-widget case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * style(ui): run organize-imports + eslint --fix + prettier over the sweep's changed files ui-checkstyle failed on PR #30780 with a large "ESLint + Prettier + Organise Imports (src)" file list — the gate re-runs the auto-fixers (organize- imports-cli, `eslint --fix`, `prettier --write`) against every file changed vs origin/main and fails if that leaves a diff. The whole Typography sweep (this branch's full stack on top of antd-migration/wave-1) consistently used single-quoted JSX attributes (`as='h5'`, `size='text-md'`) where the project's .prettierrc.yaml (singleQuote: true, but JSX attributes always use double quotes as part of the JSX spec Prettier follows) expects double quotes, plus a handful of import/attribute wrapping differences — none of it semantic, all of it mechanical. Ran `make ui-checkstyle-changed` (organize-imports:cli, then `yarn lint:base --fix`, then `yarn pretty:base --write`, in that order so Prettier has final say) against the full file list this PR's stack changed vs origin/main. organize-imports and i18n/app-docs generation found nothing to change; Prettier and ESLint's autofix corrected quoting/wrapping only. Verified no semantic changes: `tsc --noEmit` reports the same 524 pre-existing errors before and after (same file set, byte-for-byte), and `eslint` reports the same 1402 warnings / 0 errors as this PR's original CI run. `prettier --check` and `eslint` (no --fix) both now pass clean over the same file list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(ui): modernize SignInPage heading spacing and color Replaces the sibling margin-top rules in login.style.less with a flex gap on the .login-box container (already display:flex), and drops the .header-text/.login-form margin rules those replaced. The heading keeps as="h3" so the page's main heading retains heading semantics (core Typography defaults to span), uses the semantic tw:text-primary token rather than a raw palette value so dark mode is carried, and uses a responsive tw:gap-6 md:tw:gap-10 to preserve the breakpoint reductions the deleted .less rules had at 670px and 1200px. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): restore inline layout for search suggestion fqn text 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> * fix(ui): stop persona-switch and profile-link clicks from being swallowed 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> * fix(ui): re-wire test case card selection after Typography ellipsis change 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> * fix(ui-core): drop Typography's block wrapper for span/div 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. * fix(ui): address Typography sweep review findings 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. * test(ui): refresh three visual baselines for restored inline flow 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. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The bug
Typographywithellipsis={{ tooltip: … }}wraps its content inTooltipTrigger, which renders a react-ariaButton. react-aria'susePressdefaultsshouldStopPropagationtotrue, so a click on truncated text never reaches an ancestor'sonClick.That wrapper exists purely to host a hover/focus tooltip over non-interactive text. Swallowing clicks is not intended behavior there.
Real breakage this caused
Surfaced during the antd → ui-core-components Typography migration (#30780):
AddTestCaseList) — cards couldn't be selected at all; three Playwright specs hung waiting on API calls that never fired.There are ~57
ellipsis={{ tooltip: true }}call sites inopenmetadata-ui. Only a few sit on e2e-covered paths, so an unknown number of click targets are broken today with nothing watching — which is why this is fixed in core rather than at call sites.The fix
Pass
onPress={(e) => e.continuePropagation()}to the singleTooltipTriggerinside Typography's ellipsis branch. This is react-aria's own documented escape hatch (@react-types/shared: "the default … is not to propagate. This can be overridden by calling continuePropagation()"), verified against the installed@react-aria/interactionssource rather than docs alone.Deliberately scoped to Typography, not the shared
TooltipTrigger. Auditing consumers (form-item-label,input/label,input,table,avatar-add-button) found thattable.tsx's sortable-column help icon relies on the swallowing default — clicking it must not also trigger column sort. A global default change would have regressed that.No visual or className changes; truncation, line-clamp, width behavior and tooltip appearance are untouched.
Tests
4 new cases in
typography.test.tsx: click propagates to an ancestor handler (the regression guard), tooltip still opens on hover, tooltip still opens on keyboard focus (a11y guard), and non-ellipsis Typography unaffected. Verified failing-before by stashing only thetypography.tsxchange. After: 11/11 in typography, 15/15 package-wide. Lint, prettier,tsc --noEmitclean.For reviewers
Any call site that accidentally relied on the old swallow as a click guard will now see its ancestor
onClickfire. I audited the core package; a sweep ofopenmetadata-uicall sites is worth a look during review.Fixes #30803
🤖 Generated with Claude Code
Greptile Summary
The PR restores ancestor click propagation specifically for Typography’s ellipsis tooltip wrapper while preserving the shared TooltipTrigger’s default behavior.
onPresshandler that callscontinuePropagation().Confidence Score: 5/5
The PR appears safe to merge, with the propagation change narrowly scoped and covered by behavior-focused tests.
The implementation restores the intended ancestor click behavior only for ellipsis-wrapped Typography while leaving other TooltipTrigger consumers unchanged, and no concrete regression remains established.
Important Files Changed
Reviews (1): Last reviewed commit: "fix(ui-core): stop Typography ellipsis t..." | Re-trigger Greptile