Component selection shortcut (#1139)
This PR introduces a new keyboard shortcut to improve the efficiency of
selecting components in the app. Users can now quickly select components
using Meta + Shift + C for Mac and Ctrl + Shift + C for Other devices
(Windows/Linux)
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Add a shortcut to quickly activate the component selector from the
preview. Use Meta+Shift+C on macOS and Ctrl+Shift+C on Windows/Linux.
- **New Features**
- Added useShortcut hook to handle key combos and prevent default on
match.
- Wired shortcut in PreviewIframe with OS detection for Meta vs Ctrl.
- Forwarded keydown events from the iframe to the parent via postMessage
(dyad-shortcut-triggered) so the shortcut works inside preview content.
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
committed by
GitHub
parent
207f3fc397
commit
6ee1a93187
80
src/hooks/useShortcut.ts
Normal file
80
src/hooks/useShortcut.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function useShortcut(
|
||||
key: string,
|
||||
modifiers: { ctrl?: boolean; shift?: boolean; meta?: boolean },
|
||||
callback: () => void,
|
||||
isComponentSelectorInitialized: boolean,
|
||||
iframeRef?: React.RefObject<HTMLIFrameElement | null>,
|
||||
): void {
|
||||
useEffect(() => {
|
||||
const isModifierActive = (
|
||||
modKey: boolean | undefined,
|
||||
eventKey: boolean,
|
||||
) => (modKey ? eventKey : true);
|
||||
|
||||
const validateShortcut = (
|
||||
eventKey: string,
|
||||
eventModifiers: { ctrl?: boolean; shift?: boolean; meta?: boolean },
|
||||
) => {
|
||||
const keyMatches = eventKey === key.toLowerCase();
|
||||
const ctrlMatches = isModifierActive(
|
||||
modifiers.ctrl,
|
||||
eventModifiers.ctrl || false,
|
||||
);
|
||||
const shiftMatches = isModifierActive(
|
||||
modifiers.shift,
|
||||
eventModifiers.shift || false,
|
||||
);
|
||||
const metaMatches = isModifierActive(
|
||||
modifiers.meta,
|
||||
eventModifiers.meta || false,
|
||||
);
|
||||
|
||||
if (
|
||||
keyMatches &&
|
||||
ctrlMatches &&
|
||||
shiftMatches &&
|
||||
metaMatches &&
|
||||
isComponentSelectorInitialized
|
||||
) {
|
||||
callback();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (
|
||||
validateShortcut(event.key.toLowerCase(), {
|
||||
ctrl: event.ctrlKey,
|
||||
shift: event.shiftKey,
|
||||
meta: event.metaKey,
|
||||
})
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
const handleMessageEvent = (event: MessageEvent) => {
|
||||
// Only handle messages from our iframe
|
||||
if (event.source !== iframeRef?.current?.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data?.type === "dyad-select-component-shortcut") {
|
||||
if (isComponentSelectorInitialized) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
window.addEventListener("message", handleMessageEvent);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeyDown);
|
||||
window.removeEventListener("message", handleMessageEvent);
|
||||
};
|
||||
}, [key, modifiers, callback, isComponentSelectorInitialized, iframeRef]);
|
||||
}
|
||||
Reference in New Issue
Block a user