Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018jonfdxn1Xit9bdkNJpE4G
85 lines
2.8 KiB
JavaScript
85 lines
2.8 KiB
JavaScript
/* 202-1 — 표 칸 아래로 간 안내 줄 몫이 창 끝까지 셈(`ui_template_data_table.ts` fillViewport)에 들어가는지 단위검증 헬퍼.
|
|
* 카드 본문 = [표 칸][아래 줄][안내 줄 · 안내 줄 …](B08 `tableCard` 꼴) 가짜 DOM 에서 돌리고 JSON 으로 냄. */
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const file = path.join(__dirname, "..", "..", "ui_template", "ui_template_data_table.ts");
|
|
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
|
|
const win = { innerHeight: 900, scrollY: 0, addEventListener() {}, removeEventListener() {} };
|
|
const observers = [];
|
|
class RO {
|
|
constructor(fn) {
|
|
this.fn = fn;
|
|
observers.push(this);
|
|
}
|
|
observe() {}
|
|
disconnect() {}
|
|
}
|
|
const el = (name, css = {}, height = 0) => ({
|
|
name,
|
|
css,
|
|
height,
|
|
top: 0,
|
|
parentElement: null,
|
|
nextElementSibling: null,
|
|
isConnected: true,
|
|
style: {},
|
|
getBoundingClientRect() {
|
|
return { top: this.top, height: this.height };
|
|
},
|
|
});
|
|
function link(parent, ...kids) {
|
|
kids.forEach((k, i) => {
|
|
k.parentElement = parent;
|
|
k.nextElementSibling = kids[i + 1] ?? null;
|
|
});
|
|
return parent;
|
|
}
|
|
const sty = (n) => ({
|
|
rowGap: n.css.rowGap ?? "normal",
|
|
paddingBottom: n.css.paddingBottom ?? "0px",
|
|
borderBottomWidth: n.css.borderBottomWidth ?? "0px",
|
|
marginBottom: n.css.marginBottom ?? "0px",
|
|
});
|
|
const box = { exports: {} };
|
|
new Function("exports", "module", "require", "window", "document", "getComputedStyle", "ResizeObserver", js)(
|
|
box.exports,
|
|
box,
|
|
(p) => (p.endsWith(".css") ? {} : require(p)),
|
|
win,
|
|
{ body: null },
|
|
sty,
|
|
RO,
|
|
);
|
|
const m = box.exports;
|
|
|
|
// 문서: body(padding-bottom 8) > card(padding-bottom 12 · gap 8) > [root][avg 20][info 30][hint 40]
|
|
const body = el("body", { paddingBottom: "8px" });
|
|
const card = el("card", { paddingBottom: "12px", rowGap: "8px" });
|
|
const root = el("root");
|
|
const avg = el("avg", {}, 20);
|
|
const info = el("info", {}, 30);
|
|
const hint = el("hint", {}, 40);
|
|
link(body, card);
|
|
link(card, root, avg, info, hint);
|
|
root.top = 200;
|
|
|
|
m.fillViewport(root);
|
|
observers.forEach((o) => o.fn());
|
|
const out = { first: parseFloat(root.style.maxHeight) };
|
|
out.below = m.spaceBelow(root);
|
|
out.belowExpected = 3 * 8 + 20 + 30 + 40 + 12 + 8; // 줄 사이 8 셋 · 아래 줄 · 안내 둘 · 카드 · 본문 여백
|
|
out.bottom = root.top + out.first + out.below; // 문서 맨 아래 = 창 아래 끝(페이지 스크롤 0)
|
|
out.viewport = win.innerHeight;
|
|
|
|
// 안내 줄이 두 줄로 늘어남 → 표 칸이 그만큼 줄어듦
|
|
hint.height = 60;
|
|
observers.forEach((o) => o.fn());
|
|
out.afterHintGrow = parseFloat(root.style.maxHeight);
|
|
out.firstMinusGrow = out.first - 20;
|
|
console.log(JSON.stringify(out));
|