diff --git a/A00_Common/spreadsheet/spreadsheet_data_menu.ts b/A00_Common/spreadsheet/spreadsheet_data_menu.ts index 63721d63..431cd309 100644 --- a/A00_Common/spreadsheet/spreadsheet_data_menu.ts +++ b/A00_Common/spreadsheet/spreadsheet_data_menu.ts @@ -5,6 +5,7 @@ * 조건부 서식 · 데이터 유효성 · 이름 관리 · 시트 숨김/탭 색(sub4 패널 — 부품 오른위 창에 띄움) · 눈금선 · * 수식 분석(sub3 — 선행 · 종속 추적 화살표 · 화살표 지우기 · 수식 계산 · 오류 ⚠ 풍선) · 자동 합계(Σ · Alt+=). * 유효성 목록 칸은 고르면 칸 옆 ▼ · Alt+↓ 로 값 목록(필터 머리 칸이면 필터 목록이 먼저). + * 누를 때만 쓰는 창(정렬 · 조건부 서식 · 시트)은 `import()` 로 늦게 — 크기 예산(열 때 받는 조각). * ========================================================================== */ import "./spreadsheet_stage3.css"; // sub4 패널 스타일(잇는 쪽이 붙임) @@ -12,13 +13,10 @@ import { createMapContextMenu, type MapContextMenuItem } from "@ui/ui_template_c import { el, showToast } from "@ui/ui_template_elements"; import { parseRange, rangeToA1, toA1 } from "./spreadsheet_address"; import { autoSumRange } from "./spreadsheet_autosum"; -import { createCondFmtPanel } from "./spreadsheet_condfmt"; import { attachErrorTip } from "./spreadsheet_errcheck"; import { openEvalSteps } from "./spreadsheet_eval_steps"; import { attachFilter, toggleFilter } from "./spreadsheet_filter"; import { createNameManagerPanel } from "./spreadsheet_names"; -import { createSheetExtraPanel } from "./spreadsheet_sheet_extra"; -import { openSortDialog, sortSelection } from "./spreadsheet_sort_dialog"; import { attachTrace } from "./spreadsheet_trace"; import { createValidationDropdown, @@ -108,7 +106,11 @@ export function mountDataMenu(ctx: SpreadsheetContext, back: () => void): DataMe closePanel(); back(); }); - function openPanel(name: string, make: (c: SpreadsheetContext) => PartHandle): void { + async function openPanel( + name: string, + load: () => Promise<(c: SpreadsheetContext) => PartHandle>, + ): Promise { + const make = await load(); closePanel(); panel = make(ctx); title.textContent = name.replace("…", ""); @@ -116,15 +118,42 @@ export function mountDataMenu(ctx: SpreadsheetContext, back: () => void): DataMe dialog.removeAttribute("hidden"); } + const sorting = () => import("./spreadsheet_sort_dialog"); + async function sortQuick(desc: boolean): Promise { + (await sorting()).sortSelection(ctx, desc); + back(); + } + async function sortDialog(): Promise { + const m = await sorting(); + closeSort?.(); + closeSort = m.openSortDialog(ctx); + } + function evalSteps(): void { + closeSteps?.(); + closeSteps = openEvalSteps(ctx); + } + function openMenu(anchor: HTMLElement): void { const r = anchor.getBoundingClientRect(); const items: MapContextMenuItem[] = [ - [TEXT.sort, () => ((closeSort = openSortDialog(ctx)), undefined)], + [TEXT.sort, () => void sortDialog()], [TEXT.filterItem, () => (toggleFilter(ctx), back())], - [TEXT.condfmt, () => openPanel(TEXT.condfmt, createCondFmtPanel)], - [TEXT.validation, () => openPanel(TEXT.validation, createValidationPanel)], - [TEXT.names, () => openPanel(TEXT.names, createNameManagerPanel)], - [TEXT.sheets, () => openPanel(TEXT.sheets, createSheetExtraPanel)], + [ + TEXT.condfmt, + () => + void openPanel(TEXT.condfmt, () => + import("./spreadsheet_condfmt").then((m) => m.createCondFmtPanel), + ), + ], + [TEXT.validation, () => void openPanel(TEXT.validation, async () => createValidationPanel)], + [TEXT.names, () => void openPanel(TEXT.names, async () => createNameManagerPanel)], + [ + TEXT.sheets, + () => + void openPanel(TEXT.sheets, () => + import("./spreadsheet_sheet_extra").then((m) => m.createSheetExtraPanel), + ), + ], [TEXT.grid, () => (toggleGridlines(), back())], { label: TEXT.audit, @@ -132,7 +161,7 @@ export function mountDataMenu(ctx: SpreadsheetContext, back: () => void): DataMe [TEXT.prec, () => traced(trace.precedents())], [TEXT.dep, () => traced(trace.dependents())], [TEXT.clear, () => (trace.clear(), back())], - [TEXT.steps, () => (closeSteps?.(), (closeSteps = openEvalSteps(ctx)))], + [TEXT.steps, evalSteps], ], }, ]; @@ -201,8 +230,8 @@ export function mountDataMenu(ctx: SpreadsheetContext, back: () => void): DataMe const buttons = ctx.readOnly ? [] : [ - button("↑", TEXT.asc, () => sortSelection(ctx, false)), - button("↓", TEXT.desc, () => sortSelection(ctx, true)), + button("↑", TEXT.asc, () => void sortQuick(false), true), + button("↓", TEXT.desc, () => void sortQuick(true), true), button("필터", TEXT.filter, () => toggleFilter(ctx)), button("Σ", TEXT.sum, autosum, true), button(TEXT.menu, TEXT.menu, openMenu, true), diff --git a/A00_Common/spreadsheet/spreadsheet_extras.ts b/A00_Common/spreadsheet/spreadsheet_extras.ts index 863a8d27..2c78275d 100644 --- a/A00_Common/spreadsheet/spreadsheet_extras.ts +++ b/A00_Common/spreadsheet/spreadsheet_extras.ts @@ -12,7 +12,6 @@ import { attachComments, getComment, setComment } from "./spreadsheet_comments"; import { mountDataMenu } from "./spreadsheet_data_menu"; import type { Editor } from "./spreadsheet_editor"; import { mountFindPanel } from "./spreadsheet_find_panel"; -import { openFormatDialog } from "./spreadsheet_format_dialog"; import { createFormatPainter } from "./spreadsheet_format_painter"; import type { KeyHooks } from "./spreadsheet_keys"; import type { MouseHooks } from "./spreadsheet_mouse"; @@ -116,9 +115,9 @@ export function attachExtras( attrs: { type: "button", title: TEXT.format }, }); /** 창이 닫히면(확인 · 취소) 초점을 격자로 */ - function openFormat(): void { + async function openFormat(): Promise { if (ctx.readOnly) return; - openFormatDialog(ctx); + (await import("./spreadsheet_format_dialog")).openFormatDialog(ctx); // 늦게 — 크기 예산 const watch = new MutationObserver(() => { if (document.querySelector(".ss-fmtdlg")) return; watch.disconnect(); @@ -126,7 +125,7 @@ export function attachExtras( }); watch.observe(document.body, { childList: true }); } - fmt.addEventListener("click", openFormat); + fmt.addEventListener("click", () => void openFormat()); if (!ctx.readOnly) ed.bar.prepend(fmt, brush); // ── 데이터 단추 · 메뉴(정렬 · 필터 · 조건부 서식 · 유효성 · 이름 · 눈금선) ───────── @@ -207,7 +206,7 @@ export function attachExtras( find: (replace) => find.open(replace), pasteSpecial: () => (armed = true), comment: editMemo, - formatDialog: openFormat, + formatDialog: () => void openFormat(), ...data.keys, escape() { painter.clear();