Skip to content

refactor: tabular figures only on dense numeric data; proportional by default (OK-57876)#12452

Open
PatrickChoo wants to merge 6 commits into
OneKeyHQ:xfrom
PatrickChoo:feat/tabular-only-on-dense-data
Open

refactor: tabular figures only on dense numeric data; proportional by default (OK-57876)#12452
PatrickChoo wants to merge 6 commits into
OneKeyHQ:xfrom
PatrickChoo:feat/tabular-only-on-dense-data

Conversation

@PatrickChoo

@PatrickChoo PatrickChoo commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

OK-57876


Summary

Inverts the tabular-numerals policy shipped in #12391.

Before: SizableText defaulted fontVariant = TABULAR_NUMS and web-fonts.css carried a body { font-variant-numeric: tabular-nums } rule — so every string in the app rendered with equal-width digits.

After: text is proportional by default. Tabular figures are an explicit opt-in, applied only to numbers that are small, sit in a column, and tick — market/perps list columns, order books, trading tables, tickers, fee rows.

Supersedes #12443 (which was patching the symptoms) and fixes OK-57876.

Why invert

Tabular digits exist to keep a column aligned. A global default applies them to everything a human reads as words, where they are actively wrong:

  • NamesA1787, OneKey Pro2-1-6. Roobert's tabular 1 is ~2× wider and grows a foot serif; a name reads like a typo. (This is OK-57876.)
  • Addresses0x7a84...4444. Hex mixes digits and letters, so tabular equalizes only half the characters and the string comes out ragged — worse than either pure option.
  • Prose / marketing copy, amount input fields, and large hero balances (a single big number has no column to align with).

Under the old default each of these needed its own opt-out, and the list only ever grew. The set of surfaces that genuinely want tabular, by contrast, is bounded and enumerable: tables and tickers. So the default was on the wrong side.

Net effect: names, addresses, prose, inputs and hero numbers are now correct with zero annotations — the escape hatches for them are all deleted.

The rule

Tabular (opt-in) Small numbers in a column that tick — list/table cells, order book, tickers, fee rows
Proportional (default) Everything else — names, addresses, labels, headers, prose, inputs, hero numbers

Documented on TABULAR_NUMS in packages/components/src/utils/tabularNums.ts.

Changes

Core (@onekeyhq/components)

  • SizableText — dropped the app-wide fontVariant default (it still translates an explicit fontVariant into a real style, since Tamagui drops the raw prop).
  • web-fonts.css — dropped the global body rule.
  • tabularNums.tsTABULAR_NUMS_STYLE now always builds a real style. It previously resolved to undefined on web because the body rule covered it; without that rule, an explicit opt-in would have been a no-op on web. PROPORTIONAL_NUMS is gone — it has nothing left to escape from.
  • Badge.Text — no longer hard-codes tabular; it now honors a fontVariant prop (it is styled from raw tamagui text, which silently drops the prop).

Opt-ins — market/perps list columns, order book (incl. the raw-RN <Text> depth rows), ticker bars, perps trading tables, token/home lists, DeFi & Earn/Borrow/Staking tables, transaction history, Swap Pro, provider/quote lists, referral tables, gas-fee editors.

New shared choke-point PerpTableCellText collapses ~89 perps table cells into one component, so a new column can't silently forget.

Verification

  • tsgo --noEmit: no new errors. oxlint --type-aware --deny-warnings on all 120 files: clean.
  • Roobert's glyphs were confirmed by rendering the shipped font directly: the tabular 1 nearly doubles in width and gains a foot serif; the proportional 1 does not.
  • Live web probes assert the split in both directions per screen:
    • Market — 446 numeric cells tabular; category names, badges and all 35 addresses proportional.
    • Perps — 113 tabular (mark price, order book, funding, countdown); labels and controls proportional.
    • DeFi — APY columns tabular; the $0.00 hero proportional.

Review notes

A cross-review (local + Codex) caught real gaps in the first pass, all fixed here:

  • TxActionCommon's opt-in was dead. Real transfers pass the amount as a ReactNode, which bypassed the typeof change === 'string' branch the prop was added to — the wallet's whole transaction-history amount column was silently untouched. Fixed at the TxActionTransfer / TxActionTokenApprove sources.
  • MarketHomeList was half-converted, which is worse than untouched — its volume / market-cap / rank columns jittered against already-tabular price cells in the same table.
  • Whole modules had been missed: Staking, Referral, the two gas-fee editors, Home's perps tab, PopularTrading.

@PatrickChoo
PatrickChoo marked this pull request as ready for review July 11, 2026 14:26
@PatrickChoo
PatrickChoo marked this pull request as draft July 11, 2026 14:35
@originalix
originalix marked this pull request as ready for review July 11, 2026 14:35
@PatrickChoo
PatrickChoo marked this pull request as draft July 11, 2026 14:50
@PatrickChoo
PatrickChoo marked this pull request as ready for review July 11, 2026 15:04
function PerpsTotalUsd({
value,
isDegraded,
fontVariant = TABULAR_NUMS,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里给 PerpsTotalUsd 设了 fontVariant = TABULAR_NUMS,但这个 wrapper 不只用于持仓列表,也直接被首页和桌面 Perps 头部的 $headingXl 账户总额复用。触发条件就是 Perps 头部展示总资产时;调用方没有显式覆盖的话,hero 数字会被强制切到等宽字形,1 会明显变宽,和这次把 tabular 收窄到 dense data 的目标相反。

建议把这里的默认值去掉或改回 proportional,只在真正的列式/列表场景显式传 fontVariant={TABULAR_NUMS}

<EarnText
text={description}
size="$bodyLgMedium"
fontVariant={TABULAR_NUMS}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里把 GridItemV2description 槽位统一传成了 fontVariant={TABULAR_NUMS}。触发 provider / profit 这类后端驱动卡片时,只要 description.text 不是纯数字而是普通 IEarnText,这个通用组件就会替调用方强行开启等宽数字。

结果是字体策略重新从业务调用点回流到了基础卡片层,后续任何带数字的说明文本都会被同一层默认值误伤。建议让 GridItemV2 默认保持 proportional,只在确认是数值字段的具体 item 或调用点显式传 fontVariant={TABULAR_NUMS}

*/
export function EarnAmountText({
children: text,
fontVariant = TABULAR_NUMS,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里把 EarnAmountText 默认成了 TABULAR_NUMS,但这个 wrapper 不只服务于密集数列,也被 UniversalWithdraw 这类单值大号金额直接复用,还会继续走下面的 passthrough / 混合文本分支。触发这些 one-off amount 或普通文本路径时,调用方没有显式覆盖的话,本来应该恢复 proportional 的金额也会被强制切成等宽数字。

这会把这次想收窄到业务调用点的字形决策又重新推回通用 wrapper,连组件注释里“suffix rendered as-is”的边界也一起变宽了。建议去掉这里的默认值,只让明确需要列对齐的调用点显式传 fontVariant={TABULAR_NUMS}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants