fix(sheet): 머리 칸 / 로 층 나눔 · 줄 머리 칸 고정 · 줄 머리 칸 폭 자동 (M02 재검증)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tjoit7rxvpLMM7cafeVTo1
This commit is contained in:
2026-09-25 12:45:57 +09:00
co-authored by Claude Sonnet 5
parent 4679261634
commit acca7d1fb6
7 changed files with 98 additions and 10 deletions
+20 -3
View File
@@ -9,7 +9,7 @@
import { el } from "@ui/ui_template_elements";
import { headDepth, layoutHead } from "./ui_template_sheet_header";
import { columnNames, formulaLabel, headMinWidths } from "./ui_template_sheet_labels";
import { columnNames, formulaLabel, headMinWidths, textWidth } from "./ui_template_sheet_labels";
import {
cellEditable,
isBoundColumn,
@@ -24,7 +24,8 @@ import type { SheetColumn, SheetDoc, SheetResult, SheetRow } from "./ui_template
export const KEY_UNIT = "s:unit";
const MASTER_ROWS = ["s:formula", "s:desc", "s:price"] as const;
const GUTTER = 64;
const GUTTER_MIN = 64;
const GUTTER_MAX = 140;
const DEFAULT_WIDTH = { 수: 72, 글: 96 };
export interface RenderState {
@@ -85,7 +86,23 @@ export function renderSheet(state: RenderState): HTMLElement {
const depth = headDepth(cols, doc.층);
const head = layoutHead(cols, depth);
const names = columnNames(cols);
const mins = headMinWidths(cols, depth, headFont());
const font = headFont();
const mins = headMinWidths(cols, depth, font);
// 줄 머리 칸 폭 — 층 이름 · 단위 · 식 · 들어갈 것 · 일위대가 · 합계 이름이 안 잘리게
const GUTTER = Math.min(
GUTTER_MAX,
Math.max(
GUTTER_MIN,
...[
...(doc.층 ?? []),
st("Row_Unit"),
st("Row_Formula"),
st("Row_Desc"),
st("Row_Unit_Price"),
...(doc.합계줄 ?? []).map((t) => t.이름),
].map((label) => Math.ceil(textWidth(label, font)) + 16),
),
);
const errors = new Map(state.result.오류.map((e) => [`d:${e.줄}|${e.열}`, e.까닭]));
for (const e of state.result.오류) errors.set(`t:${e.줄}|${e.열}`, e.까닭);
const frozen = Math.min(doc.보기?.틀고정?.열 ?? 0, cols.length);