Skip to content

CJK (Chinese) text renders with incorrect width — half the expected size #2

@Meson-liu

Description

@Meson-liu

Description

All text width calculations in the layout engine use string.length * theme.averageCharWidth, which treats every character as a single-width glyph. CJK characters (Chinese, Japanese, Korean) are double-width in monospace fonts, so any component containing CJK text renders at roughly half the correct width.

This is a systemic issue — it affects every component that measures text via .length, not just chip.

Steps to Reproduce

Render a chip with Chinese text:

chip "已归档"
chip "已分享"
chip "收藏" icon="star"

The pill boxes are noticeably narrower than the text they contain. Compare with Latin text of the same character count (e.g. chip "abc") which renders correctly.

Root Cause

In src/renderer/layout.ts, every measurement function computes width as:

const labelW = node.label.length * theme.averageCharWidth;

With averageCharWidth = 7.2 and the string "已归档" (3 CJK chars):

  • Current calculation: 3 × 7.2 = 21.6px
  • Expected width (each CJK char is ~2× wide in monospace): 3 × 14.4 ≈ 43.2px

This pattern appears in 44+ locations across layout.ts and svg.ts (for chip, button, text, menu, breadcrumb, checkbox, radio, toggle, status, segmented, tree, menubar, kv, combo, stat, input placeholder, tabbar, and more).

Suggested Fix

Introduce a visualTextWidth(text, averageCharWidth) helper that detects CJK characters and applies a 2× multiplier per character:

const CJK_RANGE = /[\u2E80-\u9FFF\uF900-\uFAFF\uFE30-\uFE4F\u{20000}-\u{2FA1F}]/u;

function visualTextWidth(text: string, charWidth: number): number {
  let w = 0;
  for (const ch of text) {
    w += CJK_RANGE.test(ch) ? charWidth * 2 : charWidth;
  }
  return w;
}

Then replace all node.label.length * theme.averageCharWidth calls with visualTextWidth(node.label, theme.averageCharWidth).

Environment

  • Wireloom: latest main branch
  • Rendering: SVG output (terminal/SVG renderer)
  • Font: monospace (CJK glyphs are full-width)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions