refactor(web): migrate refresh Text to Opal Text

Closed
RO
2d ago
+1099-861

Description

This is the last of four cleanup PRs on top of #16234, which is merged (stack: #16240 icons, #16241 raw elements, #16242 refresh components, #16243 Text). It migrates the deprecated refresh Text (@/refresh-components/texts/Text, a boolean-flag API) to Text from @opal/components (font and color enum props).

Before and after

BeforeAfter
Files that import refresh Text13031
Files fully on Opal Text099
opal/no-replaced-refresh-import warnings in the repo (all modules)15541

The work is in four commits. Parts 1 to 3 each cover about a third of the files. Part 4 covers 8 files that the previous PR (Card/Truncated) also changed, migrated on top of that PR's version to avoid merge conflicts. All four commits use the same mapping.

Mapping

Refresh TextOpal Text
Font flags (headingH1, mainUiBody, secondaryMono, figureSmallValue, ... 19 in all)The kebab-case enum ("heading-h1", "main-ui-body", "secondary-mono", "figure-small-value", ...)
No font flagfont="main-ui-body", always written out
Color flags text01..text05, textLight03/05, textDark03/05"text-0X", "text-light-0X", "text-dark-0X"
No color flagcolor="text-05", always written out. The refresh default is text-05, but the Opal default is text-04, so leaving it out would change the color
Several flags on one siteThe first match in the refresh precedence wins (fonts in declaration order; colors text01 to text05, then light, then dark)
inverted + text0X / inverted alone"text-inverted-0X" / "text-inverted-05". Light and dark colors ignore inverted, as before
Conditional flags (figureSmallLabel={x}, text02={d} text04={!d})Ternaries on font and color
nowrap / whitespace-nowrapwordWrap="whitespace-nowrap"
wrap-break-wordwordWrap="wrap-break-word"
asKept
line-clamp-N, truncatemaxLines={N}, maxLines={1}
text-center / text-start / text-end on a ptextPosition
text-action-selection-05 classcolor="action-selection-05"
text-action-danger-05, text-status-error-05 classescolor="status-error-05" (the same red in light and dark)
Layout classes (margin, padding, width, max-width, select-none, flex centering)Moved without change to a wrapper <div>, because Opal Text strips className
font-medium with main-ui-body; text-sm with main-ui-body; m-0! on a p outside proseDropped. Each one sets the value the preset or preflight already sets

Children: Opal Text takes string, RichStr or rich nodes.

  • JSX children and t.rich(...) output are wrapped in richNodes(...) from @opal/utils.
  • Numbers become String(n).
  • Mixed text and expressions become one template string, for example `!register ${registrationKey ?? ""}`.
  • Values that can be null get ?? "" or ?? undefined, so they still render as nothing.

In files that still have kept sites, the refresh import is named RefreshText and the Opal import is Text.

Visual differences reviewers should check

  • 2px horizontal padding. Opal Text always adds px-[2px], so every migrated site gains 2px each side. This is most visible on the inline value spans inside t.rich sentences on the billing pages. In SourceTagDetailsCard, the built-in 2px replaces the old px-0.5.
  • Wrapper divs. Where layout classes moved to a wrapper, the DOM has one more element. It looks the same in the flex contexts I saw. On the CSV footer, the wrapper is block-level where the old span was inline.
  • span to p. Four sites changed so that alignment or truncation still works: the SearchCard blurb, the SourceTagDetailsCard title and the SharedAppInputBar placeholder. Each parent is a div.
  • LineItem.tsx JSDoc example now uses the Opal syntax.

Kept on purpose (31 files still import refresh Text)

Each kept site needs an Opal Text capability that does not exist yet:

Missing in Opal TextWhere
className overrides against prose margins (my-0!, my-1!, leading-normal) in markdown renderers, or {...props} pass-throughAppPopup, MemoizedTextComponents, sharedMarkdownComponents, NRFChrome, theme Preview (3 sites)
whitespace-normal / whitespace-pre-line / whitespace-pre-wrapQueryHistoryTable (2), PlansView, ExpandableTextDisplay (3), theme Preview
italic, uppercase tracking-wider, tracking-[0.3em], leading-relaxed, leading-4MessageTextRenderer, nrf SettingsPanel (2), document-processing (3), refresh Divider
A font family or font size set through stylecraft IntroContent, BuildWelcome, UserAvatar, CustomAgentAvatar
Colors that change with group-hover, or color classes computed at runtimerefresh Divider, SourceTag (4), refresh SelectButton, craft BigButton
inline-block align-middle, or line-clamp-1 that lets a flex item shrink without nowrapHumanMessage, ExpandableContentWrapper, craft SideBar
Colors with no Opal token (text-error, text-action-text-danger-05, raw red and green with dark:)InlineFileManagement (5), OpenAPIAuthenticationModal (2), FederatedConnectorForm
A font with no Opal preset (text-xs at weight 500, custom font-mono sizes)ConnectorMultiSelect, OpenAPIAuthenticationModal
Billing CSS classes (billing-error-text, billing-option-title, billing-option-badge), and text-end on an inline spanBillingDetailsView, CheckoutView, PlansView
Its own API is the refresh TextPropsrefresh Truncated, general-layouts

The migrate-on-edit hook from #16234 will flag these files whenever an agent edits them. Most of them need an Opal Text addition first, such as whiteSpace and italic props, a tracking option and inline mode.

How Has This Been Tested?

  • Full lint (oxlint) at the top of the stack: 0 errors. 41 opal(no-replaced-refresh-import) warnings are left (31 for Text, in the kept files listed above).
  • bun run types:check at the top of the stack: "No type errors. Type coverage: 99.04% (273295 of 275932 identifiers) across 1352 files". Coverage is the same as on main.
  • pre-commit (oxfmt, oxlint, typescript-check) passed on each commit.
  • Mapping consistency: the agents that did parts 1 to 4 compared their mappings and agreed on the same table, including the explicit color="text-05" default and the RefreshText name.

Additional Options

  • [Optional] Please cherry-pick this PR to the latest release version.

Summary by CodeRabbit

  • Style
    • Updated typography across billing, administration, onboarding, search, chat, and other areas of the app for a consistent appearance.
    • Preserved existing text and interactions while improving the rendering of translated content, including emphasized text and links.
  • Bug Fixes
    • Improved handling of missing timestamps and counts to avoid displaying invalid values.