feat(804-12): 왼쪽 만약 식 = 결정된 식 + 근거 한 줄 · 고치면 굳음 + 표지(요구 695 · 696)

- 공식 줄 만약(IF) 식 = 지금 옵션 · 중간값으로 탄 갈래만(decide) · 만약이 낳은 0 · 1 접음 · 「a - -x」 → 「a + x」 · 셈은 그대로(판정 = 계산기 값)
- 바로 아래 근거 한 줄 — 옵션 비교 「지붕슬래브 「아님」 → 0」 · 수치 비교 「H = 9 > 7 → …」 · 규칙 보기 단추 없음(M01 도)
- 오른쪽 산출근거 = 같은 decide 한 벌(tex 의 만약 · 0 · 1 규칙을 걷고 decide 부름)
- 결정된 식을 고치면 그 글로 굳음(만약 사라짐 · 옵션 바꿔도 안 따라감) · 저장본에 만약이 있던 줄 = 「옵션 규칙이 풀렸음 · 되돌리려면 [되돌림]」 표지 · M01 · M02 같은 부품
- 1,518 전수 — 만약 든 388 문서 663 줄 · 결정된 식 값 = 원 식 = 셈 답 · 남은 만약 0 · 근거 1,062
- test_804_12 둘 · helper 「결정」 할일 · test_804_7 머리 단추 기대를 804-11 deleteButton 으로 고침(낡은 기대)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-08 16:04:16 +09:00
co-authored by Claude Opus 5.5
parent 9130741751
commit 7cde7acf1c
10 changed files with 264 additions and 17 deletions
+29 -5
View File
@@ -18,10 +18,12 @@ import {
DocError,
rename,
splitId,
textOf,
varId,
type FormulaDoc,
} from "../common_util/common_util_formula_doc";
import { isNum } from "../common_util/common_util_formula_doc_calc";
import { decide, hasIf, tryParse } from "../common_util/common_util_formula_doc_view";
import {
dropSyms,
freshId,
@@ -44,6 +46,8 @@ import { openFindPicker } from "../M02_MasterTemplete/M02_MasterTemplete_Find_Pi
import type { EditHooks } from "./line_stack_edit";
import { openTablePick } from "./line_stack_pick";
import { lt } from "./line_stack_text";
import { whyText } from "./line_stack_why";
import { createText } from "@ui/ui_template_text";
const clone = <T>(v: T): T => JSON.parse(JSON.stringify(v)) as T;
type Block = Extract<StackLine, { 꼴: "공식" }>;
@@ -221,7 +225,13 @@ export function buildBlock(
.map((id) => {
const v = vars.get(id);
const link = v?.연결;
const expr = lines.get(id);
const raw = lines.get(id);
// 만약 식 = 결정된 식(지금 옵션 · 중간값으로 탄 갈래만 · 요구 695) — 고치면 그 글로 굳음(만약 사라짐 · 696)
const tree = raw !== undefined ? tryParse(raw) : null;
const iffy = !!tree && hasIf(tree);
const expr = iffy ? textOf(decide(tree!, vals)) : raw;
const was = h.before?.get(id);
const freed = !iffy && raw !== undefined && !!was && hasIf(tryParse(was) ?? ["num", 0, "0"]);
const sub = link?.갈래 === "단가산출" && link.키 ? h.subDoc(link.키) : null;
const tag =
link?.갈래 === "표" && !expr
@@ -311,10 +321,11 @@ export function buildBlock(
body = [
name,
"=",
...(expr
? [tap(el("span", { className: "lstk-expr", text: shownText(expr) }), id), "="]
: []),
el("span", { className: "lstk-val", text: valText(id) }),
...(expr ? [tap(el("span", { className: "lstk-expr", text: shownText(expr) }), id)] : []),
// 결정된 식이 수 하나면(만약이 수를 탄 줄) 값을 또 적지 않음
...(expr && iffy && tryParse(expr)?.[0] === "num"
? []
: [...(expr ? ["="] : []), el("span", { className: "lstk-val", text: valText(id) })]),
];
else
body = [
@@ -327,12 +338,25 @@ export function buildBlock(
? [el("span", { className: "lstk-unit", text: shownUnit(v?.단위) })]
: []),
];
const why = iffy
? whyText(tree!, vals, {
label: (x) => vars.get(x)?.이름 || splitId(x)[1] || x,
shown: shownText,
fmt: (x) => eqText(x),
})
: "";
const notes = [
...(why ? [createText(why)] : []),
...(freed ? [createText(lt("If_Freed"), "warning")] : []),
];
notes.forEach((n) => n.classList.add("lstk-wide", "lstk-why"));
const row = el("div", {
className: `lstk-frow ${open ? "is-open" : ""}`,
children: [
...body,
...(tag ? [tag] : []),
...(tools.length ? [el("span", { className: "lstk-rtools", children: tools })] : []),
...notes,
],
});
row.dataset.sym = id;