Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2nUMUMTsqm93PbQtipo6c
78 lines
3.0 KiB
TypeScript
78 lines
3.0 KiB
TypeScript
/* =============================================================================
|
|
* M02_DF_RoundRow.ts
|
|
* 끝수 고르기 줄 — 소수 몇 자리 · 반올림/올림/버림 · 단위 표준에서 자리 제안(적용 단추)
|
|
* 칸 · 단추는 공용 작은 크기 · 글 [한, 영] 짝은 아래 TEXT
|
|
* ========================================================================== */
|
|
|
|
import { currentLanguageIndex } from "@ui/ui_template_locale";
|
|
import { createButton, el } from "@ui/ui_template_elements";
|
|
import { parseRound, ROUND_FN, type RoundMode, type RoundSpec } from "./M02_DF_Round";
|
|
|
|
const TEXT = {
|
|
Label: ["끝수", "Rounding"],
|
|
None: ["안 씀", "none"],
|
|
Places: ["소수 {n}자리", "{n} decimals"],
|
|
Suggest: ["표준 제안: 소수 {n}자리", "Standard suggests {n} decimals"],
|
|
Apply: ["적용", "Apply"],
|
|
Places_aria: ["소수자리", "Decimal places"],
|
|
Mode_aria: ["방법", "Method"],
|
|
} as const;
|
|
|
|
const tr = (key: keyof typeof TEXT, n?: number): string =>
|
|
TEXT[key][currentLanguageIndex === 1 ? 1 : 0].replace("{n}", String(n ?? ""));
|
|
|
|
export interface RoundRowOptions {
|
|
/** 출력 칸 수식(앞 = 뺀 글) — 없으면 줄을 안 그림 */
|
|
formula: string | undefined;
|
|
/** 단위 표준이 제안한 소수자리 */
|
|
suggest: number | null;
|
|
readOnly?: boolean;
|
|
/** null = 끝수 벗김 */
|
|
onApply(spec: RoundSpec | null): void;
|
|
}
|
|
|
|
export function createRoundRow(opts: RoundRowOptions): HTMLElement | null {
|
|
if (opts.formula === undefined) return null;
|
|
const now = parseRound(opts.formula)?.spec ?? null;
|
|
const places = el("select", {
|
|
className: "ui-select ui-select--sm",
|
|
attrs: { "aria-label": tr("Places_aria") },
|
|
});
|
|
places.append(el("option", { attrs: { value: "" }, text: tr("None") }));
|
|
for (let n = 0; n <= 6; n++) {
|
|
places.append(el("option", { attrs: { value: String(n) }, text: tr("Places", n) }));
|
|
}
|
|
places.value = now ? String(now.places) : "";
|
|
const mode = el("select", {
|
|
className: "ui-select ui-select--sm",
|
|
attrs: { "aria-label": tr("Mode_aria") },
|
|
});
|
|
for (const m of Object.keys(ROUND_FN) as RoundMode[]) {
|
|
mode.append(el("option", { attrs: { value: m }, text: m }));
|
|
}
|
|
mode.value = now?.mode ?? "반올림";
|
|
if (opts.readOnly) places.disabled = mode.disabled = true;
|
|
const emit = (): void =>
|
|
opts.onApply(
|
|
places.value === "" ? null : { places: Number(places.value), mode: mode.value as RoundMode },
|
|
);
|
|
places.addEventListener("change", emit);
|
|
mode.addEventListener("change", () => places.value !== "" && emit());
|
|
const row = el("div", {
|
|
className: "m02-dfpanel-row",
|
|
children: [el("span", { className: "m02-dfpanel-label", text: tr("Label") }), places, mode],
|
|
});
|
|
if (opts.suggest !== null && !now && !opts.readOnly) {
|
|
row.append(
|
|
el("span", { className: "m02-dfpanel-note", text: tr("Suggest", opts.suggest) }),
|
|
createButton({
|
|
label: tr("Apply"),
|
|
variant: "ghost",
|
|
size: "sm",
|
|
onClick: () => opts.onApply({ places: opts.suggest!, mode: "반올림" }),
|
|
}),
|
|
);
|
|
}
|
|
return row;
|
|
}
|