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:
@@ -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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user