Skip to content

Commit 83a269a

Browse files
committed
fix(pan): sync modifier key release via event flags in iframes
syncModifierKeys now writes both true and false states from event modifier flags instead of only setting keys to true. This prevents stale pressed-key state when keyup never fires (e.g. unfocused iframe). Also passes the actual clamped scale from this.state.scale to the onTransform callback instead of the pre-clamp local variable. Made-with: Cursor
1 parent 6afa64e commit 83a269a

1 file changed

Lines changed: 28 additions & 10 deletions

File tree

src/core/instance.core.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -514,18 +514,32 @@ export class ZoomPanPinch {
514514
}
515515
};
516516

517-
// Modifier keys (Ctrl, Meta/Cmd, Shift, Alt) are available on every
518-
// mouse/wheel/touch event even when the window never received keydown
519-
// (e.g. an unfocused iframe). Only SET keys here; clearing is handled
520-
// by keyup and handleWindowBlur so that explicit keydown state is
521-
// never overwritten by a gesture event that lacks modifier flags.
517+
// Iframe focus problem (e.g. Storybook):
518+
//
519+
// When the library runs inside an iframe, keyboard events (keydown/keyup)
520+
// only reach the iframe's window when it has focus. If the user navigates
521+
// via the host UI (e.g. Storybook sidebar) the iframe never receives
522+
// focus, so keydown never fires and activationKeys like Cmd/Ctrl are
523+
// invisible to pressedKeys.
524+
//
525+
// Mouse and wheel events, however, DO reach the iframe regardless of
526+
// focus — and they carry modifier flags (ctrlKey, metaKey, shiftKey,
527+
// altKey) that always reflect the real physical key state at event time.
528+
//
529+
// We sync those flags into pressedKeys on every interaction event so
530+
// that activationKeys checks work without requiring iframe focus.
531+
// Both pressed (true) AND released (false) states must be written;
532+
// writing only `true` would leave stale keys after release because
533+
// keyup never fires in an unfocused iframe.
522534
syncModifierKeys = (
523535
event: MouseEvent | WheelEvent | TouchEvent,
524536
): void => {
525-
if (event.ctrlKey) this.pressedKeys["Control"] = true;
526-
if (event.metaKey) this.pressedKeys["Meta"] = true;
527-
if (event.shiftKey) this.pressedKeys["Shift"] = true;
528-
if (event.altKey) this.pressedKeys["Alt"] = true;
537+
const { ctrlKey, metaKey, shiftKey, altKey } = event;
538+
539+
if (typeof ctrlKey === "boolean") this.pressedKeys["Control"] = ctrlKey;
540+
if (typeof metaKey === "boolean") this.pressedKeys["Meta"] = metaKey;
541+
if (typeof shiftKey === "boolean") this.pressedKeys["Shift"] = shiftKey;
542+
if (typeof altKey === "boolean") this.pressedKeys["Alt"] = altKey;
529543
};
530544

531545
setKeyPressed = (e: KeyboardEvent): void => {
@@ -618,7 +632,11 @@ export class ZoomPanPinch {
618632
this.applyTransformation();
619633
const ctx = getContext(this);
620634
this.onChangeCallbacks.forEach((callback) => callback(ctx));
621-
handleCallback(ctx, { scale, positionX, positionY }, onTransform);
635+
handleCallback(
636+
ctx,
637+
{ scale: this.state.scale, positionX, positionY },
638+
onTransform,
639+
);
622640
} else {
623641
console.error("Detected NaN set state values");
624642
}

0 commit comments

Comments
 (0)