mock: 長押しにループ方式とリスト方式を入れ、ツールバーで切り替える(T-30 単位7b)

どちらも押した位置に円形インジケータを、少し離して選択先のリストを出す。
間隔は600msで始まり1000msごとに進む(500ms/450msは早いという所感への対応)。
リスト方式は、ポインタがリストに入ると巡回を止め、離したときに指している行で確定する。
リストへ向かう動きをドラッグと取り違えないよう、リスト方式では長押し後のドラッグをしない。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ShoEXYqi8PWTjB9E86Ltot
This commit is contained in:
2026-10-23 21:07:04 +09:00
co-authored by Claude Opus 5.5
parent 37ed6d5186
commit b383fcf844
7 changed files with 258 additions and 50 deletions
+23 -22
View File
@@ -11,10 +11,12 @@ import PhySelectionLayer from "./PhySelectionLayer.vue";
import PhyBadgeLayer from "./PhyBadgeLayer.vue";
import PhyToolbar from "./PhyToolbar.vue";
import PhyProperties from "./PhyProperties.vue";
import PhyHoldOverlay from "./PhyHoldOverlay.vue";
import { normalizeSelection, nextGrid, insertionContainer, structuralNodes, visibleNodeIds } from "./logic";
import { usePhyClipboard } from "./usePhyClipboard";
import { usePhyViewport } from "./usePhyViewport";
import { usePhyCanvasPointer } from "./usePhyCanvasPointer";
import { HOLD_DELAY, HOLD_INTERVAL, type HoldMode } from "./usePhyLongPress";
import { usePhyKeyboard } from "./usePhyKeyboard";
import { usePhyCommands } from "./usePhyCommands";
import { usePhyCanvasView } from "./usePhyCanvasView";
@@ -217,6 +219,7 @@ function visibleIds(): Set<string> {
if (!focus.value) return new Set(allNodes().map((n) => n.id));
return visibleNodeIds(node(focus.value), variants.value);
}
const holdMode = ref<HoldMode>("loop");
const rangeBox = ref<{ x: number; y: number; width: number; height: number } | null>(null);
const pointer = usePhyCanvasPointer({
project: () => props.project,
@@ -236,12 +239,13 @@ const pointer = usePhyCanvasPointer({
isAncestor,
parentLabel,
pressTargets,
holdMode,
setSelection: setSel,
beginHistory: props.beginHistory,
commitHistory: props.commitHistory,
dispatch,
});
const { canvasDown, down, spaceUp, longLabel, longLabelPos, spaceHeld, holdCandidates, holdIndex } = pointer;
const { canvasDown, down, spaceUp, hold, spaceHeld } = pointer;
const keyHandler = usePhyKeyboard({
project: () => props.project,
mismatch: () => props.mismatch,
@@ -328,14 +332,18 @@ function onFocus(_id: string) {
@tree="treeOpen = !treeOpen"
@help="showHelp = true"
@focus="focus = $event"
:hold-mode="holdMode"
@hold-mode="holdMode = holdMode === 'loop' ? 'list' : 'loop'"
/>
<PhyHoldOverlay
v-if="hold.open.value"
:mode="hold.mode.value"
:pos="hold.pos.value"
:names="hold.names.value"
:index="hold.index.value"
:step="hold.step.value"
:pointing="hold.pointing.value"
/>
<div
v-if="longLabel"
class="long-label"
:style="{ left: longLabelPos.x + 'px', top: longLabelPos.y + 'px' }"
>
{{ longLabel }}
</div>
<div v-if="mismatch" class="warning">unitSize が一致しないため編集できません。</div>
<svg
ref="svg"
@@ -391,7 +399,7 @@ function onFocus(_id: string) {
:selected="selected"
:variants="variants"
:zoom="zoom"
:candidate="longLabel ? (holdCandidates[holdIndex] ?? null) : null"
:candidate="hold.open.value ? (hold.candidates.value[hold.index.value] ?? null) : null"
:parent="focus ? focusParentMatrix(focus) : undefined"
/>
<PhyBadgeLayer
@@ -456,7 +464,12 @@ function onFocus(_id: string) {
フォーカス · F2 プロパティ
</p>
<p>Ctrl+Z/Y/S Undo・Redo・保存 · ? 一覧</p>
<p>長押し: キー上で500ms待つと選択先候補が450msごとに進み、離すと確定します。</p>
<p>
長押し: キー上で{{ HOLD_DELAY }}ms待つと選択先候補が{{
HOLD_INTERVAL
}}msごとに進み、離すと確定します。
ループ方式では、そのまま動かすと選んだ先をドラッグします。リスト方式では、リストに入ると巡回が止まり、指している行で離すと確定します。
</p>
</article>
</div>
</section>
@@ -595,16 +608,4 @@ function onFocus(_id: string) {
font-size: 11px;
color: #6b520f;
}
.long-label {
position: fixed;
z-index: 3;
left: 0;
top: 0;
transform: translate(10px, 10px);
pointer-events: none;
background: #fff3d8;
border: 1px solid #c87d13;
padding: 3px 7px;
border-radius: 4px;
}
</style>