feat(device): 스프레드시트 손가락 — 톡 = 칸 고름(자판 안 뜸) · 고른 칸 · 머리 · 채우기 손잡이 끌기 = 범위 · 채우기 · 안 고른 칸 끌기 = 화면 밀기 · 두 번 톡 = 고침(손 동작 안에서 자판) · 손잡이 잡는 자리 20px · 두 손가락 = 격자 확대 (기기대응 4-2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
@@ -303,6 +303,14 @@ export function createEditor(ctx: SpreadsheetContext): Editor {
|
||||
}
|
||||
|
||||
function focus(): void {
|
||||
// 손가락 — 고칠 때만 화면 자판(기기대응 4-2) · 칸 고름만으로는 안 뜸
|
||||
if (document.documentElement.dataset.touch === "on") {
|
||||
const mode = st ? "text" : "none";
|
||||
if (ta.inputMode !== mode) {
|
||||
ta.inputMode = mode;
|
||||
if (document.activeElement === ta) ta.blur();
|
||||
}
|
||||
}
|
||||
if (document.activeElement !== ta) ta.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
|
||||
@@ -263,3 +263,16 @@
|
||||
.ss--editing .aislo-cell.is-selected.is-spill > .aislo-cell__text {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* 손가락(기기대응 4-2) — 채우기 손잡이를 키움 · 격자는 한 손가락 밀기만 브라우저에(두 손가락 = 격자 확대) */
|
||||
html[data-touch="on"] .aislo-grid__fill-handle {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin: -4px 0 0 -4px;
|
||||
}
|
||||
|
||||
@media (any-pointer: coarse) {
|
||||
.aislo-grid {
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,7 +553,12 @@ export function createGrid(ctx: SpreadsheetContext): GridHandle {
|
||||
const handleAt = sel && sel.시트 === ctx.sheet().id ? fillHandleCell() : null;
|
||||
if (handleAt) {
|
||||
const screen = screenBoxOf(handleAt.r, handleAt.c);
|
||||
if (Math.abs(x - (screen.x + screen.w)) <= 5 && Math.abs(y - (screen.y + screen.h)) <= 5) {
|
||||
// 손가락이면 손잡이 잡는 자리를 넓힘(기기대응 4-2)
|
||||
const grip = document.documentElement.dataset.touch === "on" ? 20 : 5;
|
||||
if (
|
||||
Math.abs(x - (screen.x + screen.w)) <= grip &&
|
||||
Math.abs(y - (screen.y + screen.h)) <= grip
|
||||
) {
|
||||
return { kind: "fillHandle", r: handleAt.r, c: handleAt.c };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,11 +255,61 @@ export function attachMouse(
|
||||
};
|
||||
const onLeave = (): void => hooks.hover?.(null);
|
||||
|
||||
// 손가락(기기대응 4-2) — 톡 = 칸 고름(브라우저 호환 마우스 그대로) · 고른 칸 · 행열 머리 · 채우기 손잡이에서
|
||||
// 끌기 = 범위 · 채우기(마우스 끌기와 같은 길) · 안 고른 칸에서 끌기 = 화면 밀기 ·
|
||||
// 두 번 톡 = 고침(손 동작 안에서 바로 열어 화면 자판이 뜸)
|
||||
let touchDrag = false;
|
||||
let lastTap = 0;
|
||||
const asMouse = (t: Touch, type: string): MouseEvent =>
|
||||
new MouseEvent(type, { clientX: t.clientX, clientY: t.clientY, button: 0, bubbles: true });
|
||||
const onTouchStart = (e: TouchEvent): void => {
|
||||
if (e.touches.length !== 1 || e.target === ed.ta) return;
|
||||
const t = e.touches[0];
|
||||
const hit = ctx.grid.hitTest(t.clientX, t.clientY);
|
||||
const grab =
|
||||
hit &&
|
||||
(hit.kind === "fillHandle" ||
|
||||
hit.kind === "rowHead" ||
|
||||
hit.kind === "colHead" ||
|
||||
(hit.kind === "cell" && inSelection(hit.r, hit.c)));
|
||||
if (!grab) return;
|
||||
e.preventDefault(); // 화면 밀기 대신 범위 · 호환 마우스 이벤트도 안 옴
|
||||
touchDrag = true;
|
||||
onDown(asMouse(t, "mousedown"));
|
||||
};
|
||||
const onTouchMove = (e: TouchEvent): void => {
|
||||
if (!touchDrag) return;
|
||||
e.preventDefault();
|
||||
root.dispatchEvent(asMouse(e.touches[0], "mousemove")); // 올라가 window 끌기 듣개에 닿음
|
||||
};
|
||||
const onTouchEnd = (e: TouchEvent): void => {
|
||||
if (touchDrag) {
|
||||
touchDrag = false;
|
||||
root.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, button: 0 })); // M02 칸 고르기도 받음
|
||||
}
|
||||
if (e.touches.length || e.changedTouches.length !== 1) return;
|
||||
const t = e.changedTouches[0];
|
||||
const hit = ctx.grid.hitTest(t.clientX, t.clientY);
|
||||
const now = Date.now();
|
||||
if (now - lastTap < 350 && hit?.kind === "cell" && !ed.editing() && !ctx.readOnly) {
|
||||
lastTap = 0;
|
||||
ed.begin();
|
||||
return;
|
||||
}
|
||||
lastTap = now;
|
||||
};
|
||||
|
||||
root.addEventListener("mousedown", onDown);
|
||||
root.addEventListener("dblclick", onDbl);
|
||||
root.addEventListener("mousemove", onHover);
|
||||
root.addEventListener("mouseleave", onLeave);
|
||||
root.addEventListener("touchstart", onTouchStart, { passive: false });
|
||||
root.addEventListener("touchmove", onTouchMove, { passive: false });
|
||||
root.addEventListener("touchend", onTouchEnd);
|
||||
return () => {
|
||||
root.removeEventListener("touchstart", onTouchStart);
|
||||
root.removeEventListener("touchmove", onTouchMove);
|
||||
root.removeEventListener("touchend", onTouchEnd);
|
||||
root.removeEventListener("mousemove", onHover);
|
||||
root.removeEventListener("mouseleave", onLeave);
|
||||
stopDrag?.();
|
||||
|
||||
Reference in New Issue
Block a user