Lightbox gestures and keyboard navigation

This commit is contained in:
DrMint 2022-05-07 19:55:08 +02:00
parent d648509311
commit 6d2240fb55
6 changed files with 176 additions and 103 deletions

63
package-lock.json generated
View File

@ -14,12 +14,13 @@
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",
"graphql-request": "^4.2.0", "graphql-request": "^4.2.0",
"lightgallery": "^2.4.0",
"markdown-to-jsx": "^7.1.7", "markdown-to-jsx": "^7.1.7",
"next": "^12.1.6", "next": "^12.1.6",
"nodemailer": "^6.7.5", "nodemailer": "^6.7.5",
"react": "18.1.0", "react": "18.1.0",
"react-dom": "18.1.0", "react-dom": "18.1.0",
"react-hotkeys-hook": "^3.4.4", "react-hot-keys": "^2.7.2",
"react-swipeable": "^7.0.0", "react-swipeable": "^7.0.0",
"turndown": "^7.1.1" "turndown": "^7.1.1"
}, },
@ -907,7 +908,6 @@
"version": "7.17.2", "version": "7.17.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
"dev": true,
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
}, },
@ -6275,6 +6275,14 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lightgallery": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/lightgallery/-/lightgallery-2.4.0.tgz",
"integrity": "sha512-9i/E/w3yaqs56y3k6SWIUS3JTLpeDCZIVnIuNppzAmj5KjLGy5wrFisoDUD0HdxVUdX0wHG5mjvB4h0TXtyf/w==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/lilconfig": { "node_modules/lilconfig": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
@ -6965,7 +6973,6 @@
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -7574,7 +7581,6 @@
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.4.0", "loose-envify": "^1.4.0",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
@ -7679,23 +7685,24 @@
"react": "^18.1.0" "react": "^18.1.0"
} }
}, },
"node_modules/react-hotkeys-hook": { "node_modules/react-hot-keys": {
"version": "3.4.4", "version": "2.7.2",
"resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.4.tgz", "resolved": "https://registry.npmjs.org/react-hot-keys/-/react-hot-keys-2.7.2.tgz",
"integrity": "sha512-vaORq07rWgmuF3owWRhgFV/3VL8/l2q9lz0WyVEddJnWTtKW+AOgU5YgYKuwN6h6h7bCcLG3MFsJIjCrM/5DvQ==", "integrity": "sha512-Z7eSh7SU6s52+zP+vkfFoNk0x4kgEmnwqDiyACKv53crK2AZ7FUaBLnf+vxLor3dvtId9murLmKOsrJeYgeHWw==",
"dependencies": { "dependencies": {
"hotkeys-js": "3.8.7" "hotkeys-js": "^3.8.1",
"prop-types": "^15.7.2"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=16.8.1", "@babel/runtime": ">=7.10.0",
"react-dom": ">=16.8.1" "react": ">=16.9.0",
"react-dom": ">=16.9.0"
} }
}, },
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
"dev": true
}, },
"node_modules/react-swipeable": { "node_modules/react-swipeable": {
"version": "7.0.0", "version": "7.0.0",
@ -7734,8 +7741,7 @@
"node_modules/regenerator-runtime": { "node_modules/regenerator-runtime": {
"version": "0.13.9", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
"dev": true
}, },
"node_modules/regexp.prototype.flags": { "node_modules/regexp.prototype.flags": {
"version": "1.4.3", "version": "1.4.3",
@ -9605,7 +9611,6 @@
"version": "7.17.2", "version": "7.17.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
"dev": true,
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
@ -13768,6 +13773,11 @@
"type-check": "~0.4.0" "type-check": "~0.4.0"
} }
}, },
"lightgallery": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/lightgallery/-/lightgallery-2.4.0.tgz",
"integrity": "sha512-9i/E/w3yaqs56y3k6SWIUS3JTLpeDCZIVnIuNppzAmj5KjLGy5wrFisoDUD0HdxVUdX0wHG5mjvB4h0TXtyf/w=="
},
"lilconfig": { "lilconfig": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
@ -14265,8 +14275,7 @@
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
"dev": true
}, },
"object-hash": { "object-hash": {
"version": "3.0.0", "version": "3.0.0",
@ -14677,7 +14686,6 @@
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"requires": { "requires": {
"loose-envify": "^1.4.0", "loose-envify": "^1.4.0",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
@ -14749,19 +14757,19 @@
"scheduler": "^0.22.0" "scheduler": "^0.22.0"
} }
}, },
"react-hotkeys-hook": { "react-hot-keys": {
"version": "3.4.4", "version": "2.7.2",
"resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.4.tgz", "resolved": "https://registry.npmjs.org/react-hot-keys/-/react-hot-keys-2.7.2.tgz",
"integrity": "sha512-vaORq07rWgmuF3owWRhgFV/3VL8/l2q9lz0WyVEddJnWTtKW+AOgU5YgYKuwN6h6h7bCcLG3MFsJIjCrM/5DvQ==", "integrity": "sha512-Z7eSh7SU6s52+zP+vkfFoNk0x4kgEmnwqDiyACKv53crK2AZ7FUaBLnf+vxLor3dvtId9murLmKOsrJeYgeHWw==",
"requires": { "requires": {
"hotkeys-js": "3.8.7" "hotkeys-js": "^3.8.1",
"prop-types": "^15.7.2"
} }
}, },
"react-is": { "react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
"dev": true
}, },
"react-swipeable": { "react-swipeable": {
"version": "7.0.0", "version": "7.0.0",
@ -14792,8 +14800,7 @@
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.13.9", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
"dev": true
}, },
"regexp.prototype.flags": { "regexp.prototype.flags": {
"version": "1.4.3", "version": "1.4.3",

View File

@ -21,12 +21,13 @@
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",
"graphql-request": "^4.2.0", "graphql-request": "^4.2.0",
"lightgallery": "^2.4.0",
"markdown-to-jsx": "^7.1.7", "markdown-to-jsx": "^7.1.7",
"next": "^12.1.6", "next": "^12.1.6",
"nodemailer": "^6.7.5", "nodemailer": "^6.7.5",
"react": "18.1.0", "react": "18.1.0",
"react-dom": "18.1.0", "react-dom": "18.1.0",
"react-hotkeys-hook": "^3.4.4", "react-hot-keys": "^2.7.2",
"react-swipeable": "^7.0.0", "react-swipeable": "^7.0.0",
"turndown": "^7.1.1" "turndown": "^7.1.1"
}, },

View File

@ -39,19 +39,23 @@ export default function AppLayout(props: Props): JSX.Element {
const handlers = useSwipeable({ const handlers = useSwipeable({
onSwipedLeft: (SwipeEventData) => { onSwipedLeft: (SwipeEventData) => {
if (SwipeEventData.velocity < sensibilitySwipe) return; if (appLayout.menuGestures) {
if (appLayout.mainPanelOpen) { if (SwipeEventData.velocity < sensibilitySwipe) return;
appLayout.setMainPanelOpen(false); if (appLayout.mainPanelOpen) {
} else if (subPanel && contentPanel) { appLayout.setMainPanelOpen(false);
appLayout.setSubPanelOpen(true); } else if (subPanel && contentPanel) {
appLayout.setSubPanelOpen(true);
}
} }
}, },
onSwipedRight: (SwipeEventData) => { onSwipedRight: (SwipeEventData) => {
if (SwipeEventData.velocity < sensibilitySwipe) return; if (appLayout.menuGestures) {
if (appLayout.subPanelOpen) { if (SwipeEventData.velocity < sensibilitySwipe) return;
appLayout.setSubPanelOpen(false); if (appLayout.subPanelOpen) {
} else { appLayout.setSubPanelOpen(false);
appLayout.setMainPanelOpen(true); } else {
appLayout.setMainPanelOpen(true);
}
} }
}, },
}); });

View File

@ -1,5 +1,6 @@
import { Dispatch, SetStateAction, useCallback } from "react"; import { Dispatch, SetStateAction } from "react";
import { useHotkeys } from "react-hotkeys-hook"; import Hotkeys from "react-hot-keys";
import { useSwipeable } from "react-swipeable";
import Img from "./Img"; import Img from "./Img";
import Button from "./Inputs/Button"; import Button from "./Inputs/Button";
import Popup from "./Popup"; import Popup from "./Popup";
@ -16,46 +17,73 @@ interface Props {
export default function LightBox(props: Props): JSX.Element { export default function LightBox(props: Props): JSX.Element {
const { state, setState, images, index, setIndex } = props; const { state, setState, images, index, setIndex } = props;
const handlePrevious = useCallback(() => {
setIndex((previousIndex) => (previousIndex > 0 ? previousIndex - 1 : 0));
}, [setIndex]);
const handleNext = useCallback(() => { function handlePrevious() {
setIndex((previousIndex) => if (index > 0) setIndex(index - 1);
previousIndex < images.length - 1 ? previousIndex + 1 : images.length - 1 }
);
}, [images.length, setIndex]);
useHotkeys("left", handlePrevious); function handleNext() {
useHotkeys("right", handleNext); if (index < images.length - 1) setIndex(index + 1);
}
const sensibilitySwipe = 0.5;
const handlers = useSwipeable({
onSwipedLeft: (SwipeEventData) => {
if (SwipeEventData.velocity < sensibilitySwipe) return;
handleNext();
},
onSwipedRight: (SwipeEventData) => {
if (SwipeEventData.velocity < sensibilitySwipe) return;
handlePrevious();
},
});
return ( return (
<> <>
{state && ( {state && (
<Popup setState={setState} state={state} fillViewport> <Hotkeys
<div keyName="left,right"
className="grid grid-cols-[4em,1fr,4em] place-items-center allowRepeat
gap-4 w-full h-full overflow-hidden" onKeyDown={(keyName) => {
> if (keyName === "left") {
<div> handlePrevious();
{index > 0 && ( } else {
<Button onClick={handlePrevious}> handleNext();
<span className="material-icons">chevron_left</span> }
</Button> }}
)} >
</div> <Popup setState={setState} state={state} padding={false} fillViewport>
<div
{...handlers}
className={`grid grid-cols-[4em,1fr,4em] mobile:grid-cols-2
[grid-template-areas:"left_image_right"]
mobile:[grid-template-areas:"image_image""left_right"]
place-items-center first-letter:gap-4 w-full h-full overflow-hidden`}
>
<div className="[grid-area:left]">
{index > 0 && (
<Button onClick={handlePrevious}>
<span className="material-icons">chevron_left</span>
</Button>
)}
</div>
<Img className="max-h-full" image={images[index]} /> <Img
className="max-h-full [grid-area:image]"
image={images[index]}
/>
<div> <div className="[grid-area:right]">
{index < images.length - 1 && ( {index < images.length - 1 && (
<Button onClick={handleNext}> <Button onClick={handleNext}>
<span className="material-icons">chevron_right</span> <span className="material-icons">chevron_right</span>
</Button> </Button>
)} )}
</div>
</div> </div>
</div> </Popup>
</Popup> </Hotkeys>
)} )}
</> </>
); );

View File

@ -1,4 +1,6 @@
import { Dispatch, SetStateAction } from "react"; import { useAppLayout } from "contexts/AppLayoutContext";
import { Dispatch, SetStateAction, useEffect } from "react";
import Hotkeys from "react-hot-keys";
interface Props { interface Props {
setState: setState:
@ -8,42 +10,65 @@ interface Props {
children: React.ReactNode; children: React.ReactNode;
fillViewport?: boolean; fillViewport?: boolean;
hideBackground?: boolean; hideBackground?: boolean;
padding?: boolean;
} }
export default function Popup(props: Props): JSX.Element { export default function Popup(props: Props): JSX.Element {
const {
setState,
state,
children,
fillViewport,
hideBackground,
padding = true,
} = props;
const appLayout = useAppLayout();
useEffect(() => {
appLayout.setMenuGestures(!state);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state]);
return ( return (
<div <Hotkeys
className={`fixed inset-0 z-50 grid place-content-center keyName="escape"
transition-[backdrop-filter] duration-500 ${ allowRepeat
props.state onKeyDown={() => {
? "[backdrop-filter:blur(2px)]" setState(false);
: "pointer-events-none touch-none" }}
}`}
> >
<div <div
className={`fixed bg-shade inset-0 transition-all duration-500 ${ className={`fixed inset-0 z-50 grid place-content-center
props.state ? "bg-opacity-50" : "bg-opacity-0" transition-[backdrop-filter] duration-500 ${
}`} state ? "[backdrop-filter:blur(2px)]" : "pointer-events-none touch-none"
onClick={() => { }`}
props.setState(false);
}}
/>
<div
className={`p-10 grid gap-4 place-items-center transition-transform ${
props.state ? "scale-100" : "scale-0"
} ${
props.fillViewport
? "absolute inset-10"
: "relative max-h-[80vh] overflow-y-auto mobile:w-[85vw]"
} ${
props.hideBackground
? ""
: "bg-light rounded-lg shadow-2xl shadow-shade"
}`}
> >
{props.children} <div
className={`fixed bg-shade inset-0 transition-all duration-500 ${
state ? "bg-opacity-50" : "bg-opacity-0"
}`}
onClick={() => {
setState(false);
}}
/>
<div
className={`${
padding && "p-10 mobile:p-6"
} grid gap-4 place-items-center transition-transform ${
state ? "scale-100" : "scale-0"
} ${
fillViewport
? "absolute inset-10"
: "relative max-h-[80vh] overflow-y-auto mobile:w-[85vw]"
} ${
hideBackground ? "" : "bg-light rounded-lg shadow-2xl shadow-shade"
}`}
>
{children}
</div>
</div> </div>
</div> </Hotkeys>
); );
} }

View File

@ -1,6 +1,6 @@
import useDarkMode from "hooks/useDarkMode"; import useDarkMode from "hooks/useDarkMode";
import useStateWithLocalStorage from "hooks/useStateWithLocalStorage"; import useStateWithLocalStorage from "hooks/useStateWithLocalStorage";
import React, { ReactNode, useContext } from "react"; import React, { ReactNode, useContext, useState } from "react";
interface AppLayoutState { interface AppLayoutState {
subPanelOpen: boolean | undefined; subPanelOpen: boolean | undefined;
@ -14,6 +14,7 @@ interface AppLayoutState {
currency: string | undefined; currency: string | undefined;
playerName: string | undefined; playerName: string | undefined;
preferredLanguages: string[] | undefined; preferredLanguages: string[] | undefined;
menuGestures: boolean;
setSubPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>; setSubPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
setConfigPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>; setConfigPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
setMainPanelReduced: React.Dispatch< setMainPanelReduced: React.Dispatch<
@ -31,6 +32,7 @@ interface AppLayoutState {
setPreferredLanguages: React.Dispatch< setPreferredLanguages: React.Dispatch<
React.SetStateAction<string[] | undefined> React.SetStateAction<string[] | undefined>
>; >;
setMenuGestures: React.Dispatch<React.SetStateAction<boolean>>;
} }
/* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/no-empty-function */
@ -46,6 +48,7 @@ const initialState: AppLayoutState = {
currency: "USD", currency: "USD",
playerName: "", playerName: "",
preferredLanguages: [], preferredLanguages: [],
menuGestures: true,
setSubPanelOpen: () => {}, setSubPanelOpen: () => {},
setMainPanelReduced: () => {}, setMainPanelReduced: () => {},
setMainPanelOpen: () => {}, setMainPanelOpen: () => {},
@ -57,6 +60,7 @@ const initialState: AppLayoutState = {
setCurrency: () => {}, setCurrency: () => {},
setPlayerName: () => {}, setPlayerName: () => {},
setPreferredLanguages: () => {}, setPreferredLanguages: () => {},
setMenuGestures: () => {},
}; };
/* eslint-enable @typescript-eslint/no-empty-function */ /* eslint-enable @typescript-eslint/no-empty-function */
@ -115,6 +119,8 @@ export function AppContextProvider(props: Props): JSX.Element {
string[] | undefined string[] | undefined
>("preferredLanguages", initialState.preferredLanguages); >("preferredLanguages", initialState.preferredLanguages);
const [menuGestures, setMenuGestures] = useState(false);
return ( return (
<AppContext.Provider <AppContext.Provider
value={{ value={{
@ -129,6 +135,7 @@ export function AppContextProvider(props: Props): JSX.Element {
currency, currency,
playerName, playerName,
preferredLanguages, preferredLanguages,
menuGestures,
setSubPanelOpen, setSubPanelOpen,
setConfigPanelOpen, setConfigPanelOpen,
setMainPanelReduced, setMainPanelReduced,
@ -140,6 +147,7 @@ export function AppContextProvider(props: Props): JSX.Element {
setCurrency, setCurrency,
setPlayerName, setPlayerName,
setPreferredLanguages, setPreferredLanguages,
setMenuGestures,
}} }}
> >
{props.children} {props.children}