mock: 長押しの処理を usePhyLongPress に切り出す(T-30 単位7a)

候補・巡回のタイマー・表示ラベルを usePhyLongPress に移し、
usePhyCanvasPointer はドラッグ・クリックとの接続だけを持つ。挙動は変えない。
7b で2方式を入れる土台にする。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKxNtqjjPyttUfT1TgC7Qt
This commit is contained in:
2026-10-23 08:36:09 +09:00
co-authored by Claude Opus 5.5
parent 50e672768b
commit b314309e8c
2 changed files with 107 additions and 50 deletions
+88
View File
@@ -0,0 +1,88 @@
import { ref } from "vue";
type Options = {
parentLabel: (id: string | null) => string;
pressTargets: (id: string) => string[];
};
export type LongPressPick = { id: string; shift: boolean };
// キーの長押しで、キー → 親 → … の順に選択先を巡回する。
// ポインタの扱い(ドラッグ・クリック)は呼び出し側が持ち、ここは候補と表示だけを持つ。
export function usePhyLongPress(options: Options) {
const label = ref("");
const labelPos = ref({ x: 0, y: 0 });
const candidates = ref<string[]>([]);
const index = ref(0);
let timer: number | undefined;
let cycle: number | undefined;
let shift = false;
let activated = false;
function reset() {
activated = false;
}
function start(event: PointerEvent, keyId: string) {
candidates.value = options.pressTargets(keyId);
index.value = 0;
shift = event.shiftKey;
timer = window.setTimeout(() => {
if (candidates.value.length <= 1) return;
activated = true;
index.value = 1;
labelPos.value = { x: event.clientX, y: event.clientY };
label.value = `${options.parentLabel(candidates.value[1]!)} 2/${candidates.value.length}`;
cycle = window.setInterval(() => {
index.value = (index.value + 1) % candidates.value.length;
const id = candidates.value[index.value]!;
const name = index.value === 0 ? "キー" : options.parentLabel(id);
label.value = `${name} ${index.value + 1}/${candidates.value.length}`;
}, 450);
}, 500);
}
function cycling() {
return label.value !== "";
}
function cancelPending() {
if (timer && !label.value) {
window.clearTimeout(timer);
timer = undefined;
}
}
function take(): LongPressPick {
const id = candidates.value[index.value]!;
if (cycle) window.clearInterval(cycle);
label.value = "";
return { id, shift };
}
function finish(): LongPressPick | null {
if (timer) window.clearTimeout(timer);
if (cycle) window.clearInterval(cycle);
const id = label.value ? candidates.value[index.value] : undefined;
label.value = "";
return id ? { id, shift } : null;
}
function wasActivated() {
return activated;
}
return {
label,
labelPos,
candidates,
index,
reset,
start,
cycling,
cancelPending,
take,
finish,
wasActivated,
};
}