Prevent cmd-k key listener interference

This commit is contained in:
Sam Becker 2024-02-22 22:53:42 -06:00
parent 68775381d1
commit 25cb686ace
6 changed files with 63 additions and 41 deletions

View File

@ -94,11 +94,11 @@ export default function RootLayout({
</main>
<CommandK />
</ThemeProviderClient>
<Analytics debug={false} />
<SpeedInsights debug={false} />
<PhotoEscapeHandler />
<ToasterWithThemes />
</AppStateProvider>
<Analytics />
<SpeedInsights />
<PhotoEscapeHandler />
<ToasterWithThemes />
</body>
</html>
);

View File

@ -40,6 +40,7 @@ export default function CommandKClient({
const {
isCommandKOpen: isOpen,
setIsCommandKOpen: setIsOpen,
setShouldRespondToKeyboardCommands,
} = useAppState();
const isOpenRef = useRef(isOpen);
@ -103,12 +104,15 @@ export default function CommandKClient({
}, [queryLive]);
useEffect(() => {
if (!isOpen) {
if (isOpen) {
setShouldRespondToKeyboardCommands?.(false);
} else if (!isOpen) {
setQueryLive('');
setQueriedSections([]);
setIsLoading(false);
setTimeout(() => setShouldRespondToKeyboardCommands?.(true), 500);
}
}, [isOpen]);
}, [isOpen, setShouldRespondToKeyboardCommands]);
const sectionTheme: CommandKSection = {
heading: 'Theme',

View File

@ -1,6 +1,7 @@
'use client';
import { getEscapePath } from '@/site/paths';
import { useAppState } from '@/state';
import { useRouter, usePathname } from 'next/navigation';
import { useEffect } from 'react';
@ -11,17 +12,21 @@ export default function PhotoEscapeHandler() {
const pathname = usePathname();
const { shouldRespondToKeyboardCommands } = useAppState();
const escapePath = getEscapePath(pathname);
useEffect(() => {
const onKeyUp = (e: KeyboardEvent) => {
if (e.key.toUpperCase() === 'ESCAPE' && escapePath) {
router.push(escapePath, { scroll: false });
if (shouldRespondToKeyboardCommands) {
const onKeyUp = (e: KeyboardEvent) => {
if (e.key.toUpperCase() === 'ESCAPE' && escapePath) {
router.push(escapePath, { scroll: false });
};
};
};
window.addEventListener(LISTENER_KEYUP, onKeyUp);
return () => window.removeEventListener(LISTENER_KEYUP, onKeyUp);
}, [router, escapePath]);
window.addEventListener(LISTENER_KEYUP, onKeyUp);
return () => window.removeEventListener(LISTENER_KEYUP, onKeyUp);
}
}, [shouldRespondToKeyboardCommands, router, escapePath]);
return null;
}

View File

@ -30,40 +30,46 @@ export default function PhotoLinks({
}) {
const router = useRouter();
const { setNextPhotoAnimation } = useAppState();
const {
setNextPhotoAnimation,
shouldRespondToKeyboardCommands,
} = useAppState();
const previousPhoto = getPreviousPhoto(photo, photos);
const nextPhoto = getNextPhoto(photo, photos);
useEffect(() => {
const onKeyUp = (e: KeyboardEvent) => {
switch (e.key.toUpperCase()) {
case 'ARROWLEFT':
case 'J':
if (previousPhoto) {
setNextPhotoAnimation?.(ANIMATION_RIGHT);
router.push(
pathForPhoto(previousPhoto, tag, camera, simulation),
{ scroll: false },
);
}
break;
case 'ARROWRIGHT':
case 'L':
if (nextPhoto) {
setNextPhotoAnimation?.(ANIMATION_LEFT);
router.push(
pathForPhoto(nextPhoto, tag, camera, simulation),
{ scroll: false },
);
}
break;
if (shouldRespondToKeyboardCommands) {
const onKeyUp = (e: KeyboardEvent) => {
switch (e.key.toUpperCase()) {
case 'ARROWLEFT':
case 'J':
if (previousPhoto) {
setNextPhotoAnimation?.(ANIMATION_RIGHT);
router.push(
pathForPhoto(previousPhoto, tag, camera, simulation),
{ scroll: false },
);
}
break;
case 'ARROWRIGHT':
case 'L':
if (nextPhoto) {
setNextPhotoAnimation?.(ANIMATION_LEFT);
router.push(
pathForPhoto(nextPhoto, tag, camera, simulation),
{ scroll: false },
);
}
break;
};
};
};
window.addEventListener(LISTENER_KEYUP, onKeyUp);
return () => window.removeEventListener(LISTENER_KEYUP, onKeyUp);
window.addEventListener(LISTENER_KEYUP, onKeyUp);
return () => window.removeEventListener(LISTENER_KEYUP, onKeyUp);
}
}, [
router,
shouldRespondToKeyboardCommands,
setNextPhotoAnimation,
previousPhoto,
nextPhoto,

View File

@ -17,6 +17,9 @@ export default function AppStateProvider({
const [nextPhotoAnimation, setNextPhotoAnimation] =
useState<AnimationConfig>();
const [shouldRespondToKeyboardCommands, setShouldRespondToKeyboardCommands] =
useState(true);
const [isCommandKOpen, setIsCommandKOpen] = useState(false);
useEffect(() => {
@ -30,9 +33,11 @@ export default function AppStateProvider({
hasLoaded,
setHasLoaded,
nextPhotoAnimation,
setNextPhotoAnimation,
shouldRespondToKeyboardCommands,
setShouldRespondToKeyboardCommands,
isCommandKOpen,
setIsCommandKOpen,
setNextPhotoAnimation,
clearNextPhotoAnimation: () => setNextPhotoAnimation?.(undefined),
}}
>

View File

@ -6,9 +6,11 @@ export interface AppStateContext {
hasLoaded?: boolean
setHasLoaded?: Dispatch<SetStateAction<boolean>>
nextPhotoAnimation?: AnimationConfig
setNextPhotoAnimation?: Dispatch<SetStateAction<AnimationConfig | undefined>>
shouldRespondToKeyboardCommands?: boolean
setShouldRespondToKeyboardCommands?: Dispatch<SetStateAction<boolean>>
isCommandKOpen?: boolean
setIsCommandKOpen?: Dispatch<SetStateAction<boolean>>
setNextPhotoAnimation?: (animation?: AnimationConfig) => void
clearNextPhotoAnimation?: () => void
}