From 74fcca7f9815daa765eae70b17ec9b370c1096e9 Mon Sep 17 00:00:00 2001 From: River <18037011+RheingoldRiver@users.noreply.github.com> Date: Thu, 2 Nov 2023 21:05:25 -0500 Subject: [PATCH] Handle press & long-press events on current pentomino window (#72) --- package-lock.json | 17 ++++- package.json | 3 +- src/components/Header/Header.tsx | 64 +++++++++++++++++-- src/components/Information/Information.tsx | 38 +++++++---- .../PentominoDisplay/PentominoDisplay.tsx | 11 +++- 5 files changed, 109 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index aa11a66..c011d5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,8 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", - "react-router-dom": "^6.16.0" + "react-router-dom": "^6.16.0", + "use-long-press": "^3.2.0" }, "devDependencies": { "@savvywombat/tailwindcss-grid-areas": "^3.1.0", @@ -5371,6 +5372,14 @@ } } }, + "node_modules/use-long-press": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.2.0.tgz", + "integrity": "sha512-uq5o2qFR1VRjHn8Of7Fl344/AGvgk7C5Mcb4aSb1ZRVp6PkgdXJJLdRrlSTJQVkkQcDuqFbFc3mDX4COg7mRTA==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", @@ -9304,6 +9313,12 @@ "tslib": "^2.0.0" } }, + "use-long-press": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.2.0.tgz", + "integrity": "sha512-uq5o2qFR1VRjHn8Of7Fl344/AGvgk7C5Mcb4aSb1ZRVp6PkgdXJJLdRrlSTJQVkkQcDuqFbFc3mDX4COg7mRTA==", + "requires": {} + }, "use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", diff --git a/package.json b/package.json index c614343..7ae4587 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", - "react-router-dom": "^6.16.0" + "react-router-dom": "^6.16.0", + "use-long-press": "^3.2.0" }, "devDependencies": { "@savvywombat/tailwindcss-grid-areas": "^3.1.0", diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 4e5dc83..c1f50a3 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -1,13 +1,19 @@ import clsx from "clsx"; -import { useContext } from "react"; +import { useContext, useRef } from "react"; import { GameStateContext } from "../GameStateProvider/GameStateProvider"; import { PENTOMINOES } from "../../pentominoes"; import { PentominoDisplay } from "../PentominoDisplay/PentominoDisplay"; import { ALL_PENTOMINO_NAMES } from "../../constants"; import { AppStateContext } from "../AppStateProvider/AppStateProvider"; +import { + OrientationActionType, + ReflectionDirection, + RotationDirection, +} from "../GameStateProvider/currentPentominoReducer"; +import { useLongPress } from "use-long-press"; export const Header = ({ ...rest }) => { - const { currentPentomino, updateCurrentPentomino, currentOrientation, pentominoColors, showKeyboardIndicators } = + const { currentPentomino, updateCurrentPentomino, pentominoColors, showKeyboardIndicators } = useContext(GameStateContext); const { appPreferences } = useContext(AppStateContext); @@ -49,12 +55,56 @@ export const Header = ({ ...rest }) => { "border-black dark:border-slate-50" )} > - + ); }; + +const CurrentPentominoDisplay = () => { + const { currentPentomino, currentOrientation, orientationDispatch, pentominoColors } = useContext(GameStateContext); + + // ensure that the normal onclick doesn't trigger when releasing the long-press hook + // by monitoring status of the mouse button + // 1. set to false on mouse down (don't know what to handle yet) + // 2. if mouse up before it's changed, fire normal event + // 3. set to true when long-press happens + // 4. if mouse up after this, do nothing + // 5. will be set back to false on next mouse-down event + const longPressTriggered = useRef(false); + + const { appPreferences } = useContext(AppStateContext); + const bind = useLongPress((e) => { + e.preventDefault(); + e.stopPropagation(); + orientationDispatch({ + type: OrientationActionType.reflect, + direction: ReflectionDirection.Y, + }); + longPressTriggered.current = true; + }); + + return ( + + ); +}; diff --git a/src/components/Information/Information.tsx b/src/components/Information/Information.tsx index 21fb42b..771cd0a 100644 --- a/src/components/Information/Information.tsx +++ b/src/components/Information/Information.tsx @@ -111,37 +111,51 @@ export const Information = () => { > About Pentominoes
-
+

Pentominoes are tiles of area 5. There are 12 distinct pentominoes, up to rotation & reflection, with each tile having somewhere between 2 (the {} tile) and 8 ( {} {}{" "} {} {}{" "} {}) distinct orientations. -

-
+

+

This puzzle game also provides a one-square-unit-area tile that you can use as terrain (the{" "} tile). -

-
+

+

There are several different ways to enjoy Pentominoes, but the common theme is that you will try to fully tile a grid of total area 60 (5x12=60) such that no pentominoes overlap or fall off the edge, and no empty squares remain (other than whatever terrain you choose to place before starting to solve the puzzle). -

-
+

+

Generally, you want to use one of each pentomino to tile the board, but you're welcome to use this app however you like, and there are no prohibitions against using a tile more than once unless you want there to be. One suggestion is to attempt to tile an area with just the {} tile. -

-
+

+

For an added challenge, you can also choose to apply "colorways" to your tiles. Then, constrain yourself to make a solve where the 4 tiles of some color must be pairwise non-adjacent; or must be adjacent; or must be adjacent and form a line spanning the grid area (this last one is especially fun in 8x8 grids with 4 squares of terrain). Setting these colorways is available in the Settings dialog. -

-
+

+

If you're new to pentominoes, feel free to "cheat" in your first few solve attempts and move terrain around, or use one piece twice - this is a single-player puzzle game, so the rules are whatever you make them to be! -

+

+ Controls +

+ Select a tile to select it. Once selected, you can reorient it in one of the following ways: +

+ +

+ Once you've oriented it as desired, click the board to place it. You can also click a placed tile to remove + it. Removing a tile also sets this tile as the current removed tile, in the same orientation it was when + placed. +

Hotkeys You can{" "} diff --git a/src/components/PentominoDisplay/PentominoDisplay.tsx b/src/components/PentominoDisplay/PentominoDisplay.tsx index 41f81b5..3af2aa2 100644 --- a/src/components/PentominoDisplay/PentominoDisplay.tsx +++ b/src/components/PentominoDisplay/PentominoDisplay.tsx @@ -55,6 +55,7 @@ export const PentominoDisplay = ({ return { class: "", style: "" }; } + // Do not return any divs because these appear inside of

elements in the Information modal. return ( { const bg = bgColor(cell, { x, y }); return ( -

)} -
+
); }) )}