From 48a213513217d5663a8932b61127b60be8ef487a Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 27 Sep 2026 20:33:55 +0900 Subject: [PATCH] =?UTF-8?q?feat(spreadsheet):=20D=20=EC=9E=87=EA=B8=B0=20?= =?UTF-8?q?=E2=80=94=20=EC=A7=84=EC=A7=9C=20A=20=EC=97=94=EC=A7=84?= =?UTF-8?q?=EA=B3=BC=20=EC=9E=AC=EA=B2=80=EC=A6=9D=20=C2=B7=20inspect=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D(window.=5F=5FaisloSheet=20=C2=B7=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C)=20=C2=B7=20=EC=8B=9C=ED=97=98=20=ED=8B=80=20?= =?UTF-8?q?=ED=95=9C=20=EB=B2=88=20=EC=8B=9C=EB=82=98=EB=A6=AC=EC=98=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - spreadsheet.ts — `inspect` 선택이면 문맥을 window.__aisloSheet 에 걺(M02 [스프레드시트 시험] 단추 전용 · destroy 때 뗌 · 1단계 검증 뒤 지움) - 시험 틀 — ssScenario()(페이지 안 한 번에 한글 · 가리키기 · 재계산 · 되돌리기 · Delete · Ctrl+Enter · 수식 입력줄 · F2) · 가짜 격자 data-addr · 진짜 분수 값 보임 · 오류 모음 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01L6KXAabDTenEU7hrDQmCKY --- A00_Common/spreadsheet/spreadsheet.ts | 12 ++ .../spreadsheet/harness_spreadsheet_d.cjs | 108 ++++++++++++++++++ .../spreadsheet/harness_spreadsheet_d.html | 6 + .../spreadsheet/spreadsheet_d_fakes.cjs | 9 +- 4 files changed, 133 insertions(+), 2 deletions(-) diff --git a/A00_Common/spreadsheet/spreadsheet.ts b/A00_Common/spreadsheet/spreadsheet.ts index 061d08b7..25f43b0e 100644 --- a/A00_Common/spreadsheet/spreadsheet.ts +++ b/A00_Common/spreadsheet/spreadsheet.ts @@ -48,6 +48,16 @@ export interface SpreadsheetOptions { onChange?: (book: Workbook) => void; /** 고름이 바뀜 — 시트 id · 활성 칸 A1 · 범위 A1 */ onSelect?: (selection: { 시트: string; 칸: string; 범위: string }) => void; + /** ⚠ 임시 — 브레인 브라우저 검증용: 문맥을 `window.__aisloSheet` 에 걺(book · 고름 · 명령 읽기). + * M02 [스프레드시트 시험] 단추만 켬 · 산출근거 카드는 안 켬 · 1단계 검증 뒤 지움. */ + inspect?: boolean; +} + +declare global { + interface Window { + /** ⚠ 임시 — `inspect` 로 연 표의 문맥(브레인 검증용) */ + __aisloSheet?: SpreadsheetContext; + } } export interface SpreadsheetHandle { @@ -139,6 +149,7 @@ export function createSpreadsheet( grid.render(); select(ctx.selection); + if (opts.inspect) window.__aisloSheet = ctx; // ⚠ 임시 — 브레인 검증용 function notify(message: string): void { toast.textContent = message; @@ -244,6 +255,7 @@ export function createSpreadsheet( return ctx.engine.snapshot(); }, destroy() { + if (window.__aisloSheet === ctx) delete window.__aisloSheet; clearTimeout(toastTimer); detachKeys(); detachMouse(); diff --git a/resources/tester/spreadsheet/harness_spreadsheet_d.cjs b/resources/tester/spreadsheet/harness_spreadsheet_d.cjs index 8d220b14..01fee11f 100644 --- a/resources/tester/spreadsheet/harness_spreadsheet_d.cjs +++ b/resources/tester/spreadsheet/harness_spreadsheet_d.cjs @@ -10,8 +10,116 @@ window.ssSample = JSON.parse(JSON.stringify(sample)); window.ss = createSpreadsheet(host, JSON.parse(JSON.stringify(sample)), { onChange: () => window.ssChanges++, onSelect: (s) => (window.ssSelect = s), + inspect: true, }); window.ssCreate = createSpreadsheet; /** 칸 입력 값(A1) */ window.ssCell = (a1, sheet = "s1") => window.ss.getDoc().시트.find((s) => s.id === sheet).칸[a1] ?? null; + +/* 한 번에 도는 시나리오 — 탭이 새로 읽혀도 끊기지 않게 페이지 안에서 합성 사건으로 조작하고 수치를 모음. + * (믿음 입력 — 진짜 키 · 마우스 · 한글 — 은 ORCA keypress · type · mouse 로 따로 잼) */ +window.ssScenario = () => { + const ta = () => document.querySelector(".ss-input"); + const at = (a1) => { + const d = document.querySelector(`[data-a1="${a1}"]`).getBoundingClientRect(); + return { + clientX: d.left + d.width / 2, + clientY: d.top + d.height / 2, + bubbles: true, + button: 0, + }; + }; + const grid = () => document.querySelector(".ss-grid-host"); + const click = (a1, extra = {}) => { + grid().dispatchEvent(new MouseEvent("mousedown", { ...at(a1), ...extra })); + window.dispatchEvent(new MouseEvent("mouseup", at(a1))); + }; + const dragTo = (from, to) => { + grid().dispatchEvent(new MouseEvent("mousedown", from)); + window.dispatchEvent(new MouseEvent("mousemove", to)); + window.dispatchEvent(new MouseEvent("mouseup", to)); + }; + const key = (k, o = {}) => + document.activeElement.dispatchEvent( + new KeyboardEvent("keydown", { key: k, bubbles: true, cancelable: true, ...o }), + ); + const type = (text) => { + const t = document.activeElement; + t.setRangeText(text, t.selectionStart, t.selectionEnd, "end"); + t.dispatchEvent(new Event("input", { bubbles: true })); + }; + const shown = (a1) => document.querySelector(`[data-a1="${a1}"]`).textContent; + const sel = () => `${ssSelect.칸}|${ssSelect.범위}`; + const out = {}; + // 한글 첫 글자 — compositionstart 로 편집 시작 · 같은 textarea 그대로 + click("L2"); + ta().dispatchEvent(new CompositionEvent("compositionstart", { data: "" })); + out.imeEditing = + document.querySelector(".ss").classList.contains("ss--editing") && + document.activeElement === ta(); + type("한"); + key("Enter"); + out.ime = [ssCell("L2"), sel()]; + // 수 · 식 · 참조 가리키기(방향키 + 누르기) · 재계산 + click("L3"); + type("2"); + key("Enter"); + type("="); + key("ArrowUp"); + out.pointKey = ta().value; + type("*"); + click("J5"); + out.pointClick = [ + ta().value, + [...document.querySelectorAll(".fg-ref")].map((x) => x.dataset.ref), + ]; + key("Enter"); + out.calc = [ssCell("L4"), shown("L4")]; + click("L3"); + type("5"); + key("Enter"); + out.recalc = shown("L4"); + // 되돌리기 · 다시 + key("z", { ctrlKey: true }); + out.undo = [ssCell("L3"), shown("L4")]; + key("y", { ctrlKey: true }); + out.redo = [ssCell("L3"), shown("L4")]; + // Delete(서식 남김) · 되돌림 + click("B4"); + key("Delete"); + out.del = ssCell("B4"); + key("z", { ctrlKey: true }); + out.delUndo = ssCell("B4"); + // 병합 · Shift/Ctrl 방향 + click("A4"); + key("ArrowRight", { shiftKey: true }); + key("ArrowRight", { shiftKey: true }); + out.shift = sel(); + click("A3"); + key("ArrowDown", { ctrlKey: true }); + out.ctrl = sel(); + // 끌어 고르기 · Ctrl+Enter + dragTo(at("P2"), at("Q3")); + out.drag = sel(); + type("=L3+1"); + key("Enter", { ctrlKey: true }); + out.ctrlEnter = ["P2", "Q2", "P3", "Q3"].map((k) => ssCell(k)?.식); + // 수식 입력줄로 고치기 + click("N2"); + const bar = document.querySelector(".ss-formula"); + bar.focus(); + bar.value = "=J4*10"; + bar.dispatchEvent(new Event("input", { bubbles: true })); + key("Enter"); + out.bar = [ssCell("N2"), shown("N2"), sel()]; + // F2 — 방향키가 글자 자리만 + click("N2"); + key("F2"); + const before = sel(); + key("ArrowLeft"); + out.f2 = [before === sel(), document.querySelector(".ss").classList.contains("ss--editing")]; + key("Escape"); + out.errors = window.ssErrors; + return JSON.stringify(out); +}; diff --git a/resources/tester/spreadsheet/harness_spreadsheet_d.html b/resources/tester/spreadsheet/harness_spreadsheet_d.html index be9d4089..19349816 100644 --- a/resources/tester/spreadsheet/harness_spreadsheet_d.html +++ b/resources/tester/spreadsheet/harness_spreadsheet_d.html @@ -23,6 +23,12 @@
+