feat(B08): 탭 구조물 · 토공 · 수리 + 구조물 보조 넷 · 구조물도 탭 지움 · 보조 탭 위 간격 8px(95-1 · 95-2)
구조물도 모달(집계표 행 누름 · 그 측점 조합 전부 · 복사본 먼저) · 공용 표 onRowClick opt-in(95-3) · 수리 상세 폭 제한 풂 · 카드 높이 화면 따라 · @container(95-4). 화면 검증 전. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
This commit is contained in:
@@ -43,6 +43,8 @@ export interface DataTableOptions {
|
||||
caption?: string;
|
||||
/** 빈 값 글(기본 「-」 · 사용자가 채울 칸은 "") */
|
||||
empty?: string;
|
||||
/** 줄 누름(본문 줄만 · 합계 제외) — 주면 줄에 `data-i`(줄 번호)·`is-clickable` 이 붙음 */
|
||||
onRowClick?: (index: number) => void;
|
||||
}
|
||||
|
||||
export interface DataTable {
|
||||
@@ -112,6 +114,7 @@ function rowHtml(
|
||||
r: DataRow,
|
||||
alt = false,
|
||||
blank = EMPTY,
|
||||
index: number | null = null,
|
||||
): string {
|
||||
let tr = "";
|
||||
for (let j = 0; j < cols.length; j++) {
|
||||
@@ -126,7 +129,9 @@ function rowHtml(
|
||||
(fmts[j] ? ' data-num=""' : "");
|
||||
tr += `<td${attrs}>${esc(txt)}</td>`;
|
||||
}
|
||||
return alt ? `<tr class="is-alt">${tr}</tr>` : `<tr>${tr}</tr>`;
|
||||
const cls = [alt && "is-alt", index !== null && "is-clickable"].filter(Boolean).join(" ");
|
||||
const data = index !== null ? ` data-i="${index}"` : "";
|
||||
return cls || data ? `<tr${cls ? ` class="${cls}"` : ""}${data}>${tr}</tr>` : `<tr>${tr}</tr>`;
|
||||
}
|
||||
|
||||
/** 그릴 줄 구간 — 밖의 줄은 빈 줄 높이(rowH px)로만 채움 */
|
||||
@@ -163,7 +168,9 @@ export function renderDataTableHtml(o: DataTableOptions, win?: RowWindow): strin
|
||||
const to = win ? Math.max(from, Math.min(win.to, n)) : n;
|
||||
let body = win ? pad(from * win.rowH, cols.length) : "";
|
||||
const blank = o.empty ?? EMPTY;
|
||||
for (let i = from; i < to; i++) body += rowHtml(cols, fmts, left, o.rows[i], i % 2 === 1, blank);
|
||||
const pick = o.onRowClick !== undefined;
|
||||
for (let i = from; i < to; i++)
|
||||
body += rowHtml(cols, fmts, left, o.rows[i], i % 2 === 1, blank, pick ? i : null);
|
||||
if (win) body += pad((n - to) * win.rowH, cols.length);
|
||||
const foot = o.total ? `<tfoot>${rowHtml(cols, fmts, left, o.total, false, blank)}</tfoot>` : "";
|
||||
const cap = o.caption ? `<caption>${esc(o.caption)}</caption>` : "";
|
||||
@@ -199,6 +206,10 @@ export function createDataTable(opts: DataTableOptions): DataTable {
|
||||
}
|
||||
};
|
||||
root.addEventListener("scroll", () => draw(false), { passive: true });
|
||||
root.addEventListener("click", (event) => {
|
||||
const row = (event.target as Element).closest<HTMLElement>("tr[data-i]");
|
||||
if (row && root.contains(row)) state.onRowClick?.(Number(row.dataset.i));
|
||||
});
|
||||
draw(true);
|
||||
return {
|
||||
root,
|
||||
|
||||
Reference in New Issue
Block a user