Files
Aislo/A00_Common/spreadsheet/spreadsheet_actions.ts
T
eomsangdonandClaude Opus 5.5 b79793ea31 feat(spreadsheet): D 시트 탭 없앰 선택 — createSpreadsheet({tabs: false})
- 탭 줄을 안 그림 · Ctrl+PageDown/PageUp · Shift+F11 을 받지 않음(브라우저 몫) · [데이터 ▾] 의 시트 숨기기 · 탭 색 빠짐
- 산출근거(시트 하나)용 · 크기 화면 28,199 B(예산 28,672)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6KXAabDTenEU7hrDQmCKY
2026-09-28 09:59:08 +09:00

144 lines
4.6 KiB
TypeScript

/* =============================================================================
* spreadsheet_actions.ts (주인 D)
* 단축키 표(sub1 `spreadsheet_shortcuts.ts`) 「안됨」 잇기 + 3차 부품 메뉴 자리([데이터 ▾] 에 붙임).
* Ctrl+Shift++ · Ctrl+- 칸 넣기 · 지우기(행 · 열 통째면 바로 · 아니면 sub1 창) · F5 · Ctrl+G 이동 ·
* Ctrl+9/0 숨김 · Ctrl+Shift+9/0 풀기 · Ctrl+B/I/U/5 글꼴 뒤집기 · Ctrl+Shift+& 바깥 테두리 ·
* Ctrl+Shift+_ 테두리 없앰 · Ctrl+; 오늘 날짜 · Ctrl+PageDown/PageUp 시트 · Shift+F11 새 시트 ·
* Shift+Alt+→/← 행 · 열 묶기 · 풀기(C 윤곽 +/- 가 접음).
* 여기는 키 · 메뉴 → 이름만 · 몸통은 `spreadsheet_actions_run.ts`(늦게 — 크기 예산).
* ========================================================================== */
import type { MapContextMenuItem } from "@ui/ui_template_context_menu";
import type { SpreadsheetContext } from "./spreadsheet_view_types";
const TEXT = {
goTo: "이동…(F5)",
freeze: "틀 고정",
freezeRow: "첫 행 고정",
freezeCol: "첫 열 고정",
freezeAt: "지금 칸 기준 고정",
unfreeze: "틀 고정 풀기",
insert: "칸 넣기…(Ctrl+Shift++)",
remove: "칸 지우기…(Ctrl+-)",
split: "텍스트 나누기…",
dedupe: "중복된 항목 제거…",
series: "연속 데이터 채우기…",
group: "묶기(Shift+Alt+→)",
ungroup: "묶음 풀기(Shift+Alt+←)",
outline: "윤곽",
};
export type Act =
| "goTo"
| "insert"
| "remove"
| "hideRows"
| "hideCols"
| "showRows"
| "showCols"
| "group"
| "ungroup"
| "outline"
| "clearBorders"
| "today"
| "next"
| "prev"
| "newSheet"
| "freezeRow"
| "freezeCol"
| "freezeAt"
| "unfreeze"
| "split"
| "dedupe"
| "series"
| `flip:${"굵게" | "기울임" | "밑줄" | "취소선"}`;
/** Ctrl+글자(e.code) → 이름 */
const CTRL: Record<string, Act> = {
KeyB: "flip:굵게",
KeyI: "flip:기울임",
KeyU: "flip:밑줄",
Digit5: "flip:취소선",
KeyG: "goTo",
Minus: "remove",
NumpadSubtract: "remove",
NumpadAdd: "insert",
Digit9: "hideRows",
Digit0: "hideCols",
Semicolon: "today", // ponytail: 시각(Ctrl+Shift+;)은 numfmt 시간 형식이 오면
PageDown: "next",
PageUp: "prev",
};
/** Ctrl+Shift+글자 → 이름 */
const CTRL_SHIFT: Record<string, Act> = {
Equal: "insert",
NumpadAdd: "insert",
Minus: "clearBorders",
Digit9: "showRows",
Digit0: "showCols",
Digit7: "outline",
PageDown: "next",
PageUp: "prev",
};
const SHEET_ACTS = new Set<Act>(["next", "prev", "newSheet"]);
/** body 에 뜬 창(.ui-confirm)이 다 닫히면 초점을 격자로 — 창을 연 바로 뒤에 부름 */
export function watchClose(back: () => void): void {
const w = new MutationObserver(() => {
if (document.querySelector("body > .ui-confirm, body > .ui-confirm__panel")) return;
w.disconnect();
back();
});
w.observe(document.body, { childList: true });
}
function pick(e: KeyboardEvent): Act | undefined {
const ctrl = e.ctrlKey || e.metaKey;
if (e.altKey)
return e.shiftKey && !ctrl
? ({ ArrowRight: "group", ArrowLeft: "ungroup" } as Record<string, Act>)[e.key]
: undefined;
if (ctrl) return (e.shiftKey ? CTRL_SHIFT : CTRL)[e.code];
if (e.key === "F5" && !e.shiftKey) return "goTo";
if (e.key === "F11" && e.shiftKey) return "newSheet";
}
export interface Actions {
key(e: KeyboardEvent): boolean;
items: MapContextMenuItem[];
}
export function mountActions(ctx: SpreadsheetContext, back: () => void): Actions {
const go = (act: Act): void =>
void import("./spreadsheet_actions_run").then((m) => m.run(ctx, back, act));
const item = (label: string, act: Act): [string, () => void] => [label, () => go(act)];
return {
key(e) {
const act = pick(e);
// 시트 탭이 없으면(산출근거) 시트 오가기 · 새 시트를 받지 않음 — 브라우저 몫으로 둠
if (!act || (SHEET_ACTS.has(act) && ctx.root.classList.contains("ss--notabs"))) return false;
go(act);
return true;
},
items: [
item(TEXT.goTo, "goTo"),
{
label: TEXT.freeze,
children: [
item(TEXT.freezeRow, "freezeRow"),
item(TEXT.freezeCol, "freezeCol"),
item(TEXT.freezeAt, "freezeAt"),
item(TEXT.unfreeze, "unfreeze"),
],
},
item(TEXT.insert, "insert"),
item(TEXT.remove, "remove"),
item(TEXT.split, "split"),
item(TEXT.dedupe, "dedupe"),
item(TEXT.series, "series"),
{ label: TEXT.outline, children: [item(TEXT.group, "group"), item(TEXT.ungroup, "ungroup")] },
],
};
}