An alignment tick when the drop proposal lands somewhere new
NSHapticFeedbackManager .alignment at propose()'s change edge — the one funnel every retarget commits through, whose existing guards (value-equal refusal, hold freeze) already make firings per-landing- spot rather than per-pixel; withdrawal stays silent (losing a target is not an alignment), and the external-file mode gets nothing. Force Touch hardware only, silent no-op elsewhere; performanceTime .default syncs the tick to the reflow the change triggers. The performer rides an injectable seam beside holdTimeout for the same reason it has one. Drag-perf card 11b85111 — the cluster's last. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -433,6 +433,13 @@ final class DragSession {
|
||||
/// (`DragSessionTests`). Nothing in the app writes it.
|
||||
@ObservationIgnored var holdTimeout: Duration = CommittedHold.timeout
|
||||
|
||||
/// Fires the alignment tick for a genuine new landing spot (`propose`). A `var` for the reason
|
||||
/// `holdTimeout` is one: the real `NSHapticFeedbackManager` call needs a Force Touch trackpad a
|
||||
/// test bundle has no way to feed, so a test substitutes a closure that counts firings instead.
|
||||
@ObservationIgnored var hapticTick: () -> Void = {
|
||||
NSHapticFeedbackManager.defaultPerformer.perform(.alignment, performanceTime: .default)
|
||||
}
|
||||
|
||||
/// **The two flags the effective operation is a function of** — `DragLocality.operation` reads
|
||||
/// these and nothing else, so these are the whole of what "a flip" means here.
|
||||
static let operationFlags: NSEvent.ModifierFlags = [.option, .command]
|
||||
@@ -680,6 +687,13 @@ final class DragSession {
|
||||
func propose(_ target: DropTarget?) {
|
||||
guard isActive, hold == nil, proposal != target else { return }
|
||||
proposal = target
|
||||
// One tick per genuine new landing spot, never per pixel: the hysteresis/dead-region model
|
||||
// above already makes retargets sparse, which is exactly the case Apple gives `.alignment`
|
||||
// for rather than the "don't overuse haptics" one a per-sample tick would land in. A
|
||||
// withdrawal (`target == nil`) is losing a target, not landing on one, so it stays silent.
|
||||
if target != nil {
|
||||
hapticTick()
|
||||
}
|
||||
}
|
||||
|
||||
/// Records which board window's surface just resolved the proposal (`RetargetOrigin`) — the
|
||||
|
||||
Reference in New Issue
Block a user