feat(ui): 공용 표 글자 14px · 열 폭 같은 비율(155-1)

- 표 글 12 → 14px(--text-body-sm) · 줄 높이 28px
- 열 폭 = 페이지 값(12px 글 기준) × 14/12 — 고정 열 left · 표 폭 함께
- 시험 test_ui_data_table 에 폭 · CSS 단정

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KYZ2HWWdUwZWYnn3tQz7X
This commit is contained in:
2026-10-09 19:07:37 +09:00
co-authored by Claude Opus 5.5
parent 09b3b50efc
commit f52331265d
4 changed files with 33 additions and 5 deletions
+14
View File
@@ -90,5 +90,19 @@ console.log(
}),
escaped: m.renderDataTableHtml({ columns: [{ key: "x", label: "<b>" }], rows: [{ x: "a&<" }] }),
noTotal: m.renderDataTableHtml({ columns: [tc], rows: [] }).includes("<tfoot>"),
scale: m.SCALE,
widths: m.renderDataTableHtml({
columns: [
{ key: "a", label: "A" },
{ key: "b", label: "B", kind: "number" },
{ key: "c", label: "C", width: 120 },
],
rows: [{ a: 1 }],
frozen: 2,
}),
css: fs.readFileSync(
path.join(__dirname, "..", "..", "ui_template", "ui_template_data_table.css"),
"utf8",
),
}),
);
+11
View File
@@ -101,3 +101,14 @@ def test_줄_누름_옵션일_때만_data_i(r):
assert '<tr class="is-alt is-clickable" data-i="1">' in pick
assert pick.count("data-i=") == 2
assert "data-i" not in r["opts"] and "is-clickable" not in r["foot"]
def test_155_1_글자_14px_열_폭_같은_비율(r):
# 155-1 — 표 글 12 → 14px · 열 폭(12px 글 기준 값)에 14/12 를 곱함 · 줄 높이 28px
assert abs(r["scale"] - 14 / 12) < 1e-9
w = r["widths"]
assert '<col style="width:112px"><col style="width:98px"><col style="width:140px">' in w
assert 'style="width:350px"' in w # 표 폭 = 112 + 98 + 140
assert 'class="is-frozen is-edge" style="left:112px"' in w # 둘째 고정 열 left 도 같이
assert "font-size: var(--text-body-sm);" in r["css"]
assert "--dt-row-h: 28px;" in r["css"]
+2 -2
View File
@@ -4,7 +4,7 @@
* ========================================================================== */
.ui-data-table {
--dt-row-h: 24px;
--dt-row-h: 28px;
--dt-zebra: var(--color-surface);
--dt-hover: color-mix(in srgb, var(--color-accent) 14%, var(--color-canvas));
--dt-head: color-mix(in srgb, var(--color-accent) 6%, var(--color-surface));
@@ -30,7 +30,7 @@
border-collapse: separate;
border-spacing: 0;
color: var(--color-text-body);
font-size: var(--text-caption);
font-size: var(--text-body-sm);
line-height: 1.3;
}
+6 -3
View File
@@ -26,7 +26,7 @@ export interface DataColumn {
decimals?: number;
/** 끝 0 지움(decimals 는 최대 자리) — 사용자가 넣는 값처럼 자리가 줄마다 다른 열 */
trim?: boolean;
/** 열 폭 px(기본 숫자 84 · 글 96) */
/** 열 폭 px(12px 글 기준 · 기본 숫자 84 · 글 96) — 그릴 때 글 비 SCALE 을 곱함 */
width?: number;
/** 맨 아래 머리 칸 풍선 글(기본 label) */
title?: string;
@@ -70,8 +70,11 @@ const EMPTY = "-";
const ESC: Record<string, string> = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" };
const esc = (s: string): string => s.replace(/[&<>"]/g, (c) => ESC[c]);
/** 글 크기 비(14px ÷ 12px) — 페이지가 준 열 폭(12px 글 기준)을 같은 비율로 넓힘 */
export const SCALE = 14 / 12;
function colWidth(c: DataColumn): number {
return c.width ?? (c.kind === "number" ? 84 : 96);
return Math.round((c.width ?? (c.kind === "number" ? 84 : 96)) * SCALE);
}
/** 값 한 칸 → [보일 글, 빈 값인지] */
@@ -226,7 +229,7 @@ export function createDataTable(opts: DataTableOptions): DataTable {
root.className = "ui-data-table";
root.tabIndex = 0; // 키보드로 표 안 스크롤
const state = { ...opts };
let win: RowWindow = { from: -1, to: -1, rowH: 24 }; // --dt-row-h · 그린 뒤 재서 고침
let win: RowWindow = { from: -1, to: -1, rowH: 28 }; // --dt-row-h · 그린 뒤 재서 고침
// 보이는 줄 근처만 그림 — 줄 1,000개를 다 배치하면 수백 ms
const draw = (force: boolean) => {
const n = state.rows.length;