Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
102 lines
3.2 KiB
JavaScript
102 lines
3.2 KiB
JavaScript
/* 180-3 B07 안내선 보이기 / 숨기기 단추 헬퍼 — `…_UI_GuideToggle.ts` 를 Node 로 돌려 JSON 한 벌로.
|
|
* 공용 단추(`ui_template_elements`)는 진짜 · 화면 그릇만 흉내(helper_153 꼴).
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const cache = new Map();
|
|
|
|
class FakeNode {
|
|
constructor(tag) {
|
|
this.tagName = tag.toUpperCase();
|
|
this.children = [];
|
|
this.dataset = {};
|
|
this.attrs = {};
|
|
this.listeners = {};
|
|
this._text = "";
|
|
this._classes = new Set();
|
|
this.disabled = false;
|
|
this.title = "";
|
|
const self = this;
|
|
this.classList = {
|
|
add: (...names) => names.forEach((n) => self._classes.add(n)),
|
|
contains: (name) => self._classes.has(name),
|
|
};
|
|
}
|
|
set className(value) {
|
|
this._classes = new Set(String(value).split(/\s+/).filter(Boolean));
|
|
}
|
|
get className() {
|
|
return [...this._classes].join(" ");
|
|
}
|
|
set textContent(value) {
|
|
this._text = String(value);
|
|
this.children = [];
|
|
}
|
|
get textContent() {
|
|
return this._text + this.children.map((c) => c.textContent).join("");
|
|
}
|
|
setAttribute(key, value) {
|
|
this.attrs[key] = String(value);
|
|
}
|
|
append(...kids) {
|
|
kids.forEach((k) => this.children.push(k));
|
|
}
|
|
addEventListener(type, handler) {
|
|
(this.listeners[type] ||= []).push(handler);
|
|
}
|
|
click() {
|
|
if (!this.disabled) (this.listeners.click || []).forEach((handler) => handler({}));
|
|
}
|
|
}
|
|
globalThis.document = { createElement: (tag) => new FakeNode(tag) };
|
|
|
|
function loadTs(file) {
|
|
const full = path.resolve(file);
|
|
if (cache.has(full)) return cache.get(full);
|
|
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
cache.set(full, box.exports);
|
|
const localRequire = (request) => {
|
|
if (request === "@ui/ui_template_elements")
|
|
return loadTs(path.join(ROOT, "ui_template", "ui_template_elements.ts"));
|
|
if (request.startsWith(".")) {
|
|
const target = path.join(path.dirname(full), `${request}.ts`);
|
|
return fs.existsSync(target) ? loadTs(target) : {};
|
|
}
|
|
return {};
|
|
};
|
|
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
|
cache.set(full, box.exports);
|
|
return box.exports;
|
|
}
|
|
|
|
const { buildGuideToggle, guideShown } = loadTs(
|
|
path.join(ROOT, "B07_DesignDetail", "B07_DesignDetail_UI_GuideToggle.ts"),
|
|
);
|
|
|
|
const sent = [];
|
|
const button = buildGuideToggle((visible) => sent.push(visible));
|
|
const view = () => ({
|
|
text: button.textContent,
|
|
cls: button.className,
|
|
pressed: button.attrs["aria-pressed"],
|
|
shown: guideShown(),
|
|
});
|
|
const out = { first: view() };
|
|
button.click();
|
|
out.hidden = view();
|
|
button.click();
|
|
out.again = view();
|
|
button.click();
|
|
out.last = view();
|
|
// 화면을 다시 세워 새 단추를 만들어도 숨김 유지(모듈 값)
|
|
const rebuilt = buildGuideToggle((visible) => sent.push(visible));
|
|
out.rebuilt = { text: rebuilt.textContent, pressed: rebuilt.attrs["aria-pressed"] };
|
|
out.sent = sent;
|
|
process.stdout.write(JSON.stringify(out));
|