hodgef / react-simple-keyboard

React Virtual Keyboard - Customizable, responsive and lightweight
https://virtual-keyboard.js.org/react
MIT License
569 stars 62 forks source link

Apply class to letter on press #837

Closed harlessmark closed 4 years ago

harlessmark commented 4 years ago

Simple-keyboard version ^2.4.68

Describe the bug React Hooks. I want to apply a CSS class to a letter when it's pressed. I have this template as my state. Setting buttons: letter.toUpperCase() works but the letter will obviously be replaced with the next letter when another is pressed. So on this line I'm using a template literal string to add the letter followed by a space for the next pressed letter but it's not working. I do see the keyboard component is receiving the new letters correctly, however, their styles are not changing.

Live site but keyboard only appears when on mobile or refreshing while devtools are open

hodgef commented 4 years ago

Hello @superhackerboy,

If I understand correctly, when a button is incorrect it should have the "incorrect-letter" class and vice-versa. Here's an example of this working:

import React, { useState, useRef } from "react";
import Title from "./Title";
import KeyboardEventHandler from "react-keyboard-event-handler";
import { useDispatch, useSelector } from "react-redux";

import Keyboard from "react-simple-keyboard";
import "react-simple-keyboard/build/css/index.css";

function Movie() {
  const { letters } = useSelector(state => state.movie);
  const { data } = useSelector(state => state.movie);
  const isMobile = useSelector(state => state.isMobile);
  const dispatch = useDispatch();

  const [layout] = useState("default");
  const keyboard = useRef();

  const [correctLetters, setCorrectLetters] = useState([]);
  const [incorrectLetters, setIncorrectLetters] = useState([]);

  const getButtonTheme = () => {
    const buttonTheme = [];

    if(correctLetters.length){
      buttonTheme.push(
        {
          class: "correct-letter",
          buttons: correctLetters.join(" "),
        }
      )
    }

    if(incorrectLetters.length){
      buttonTheme.push(
        {
          class: "incorrect-letter",
          buttons: incorrectLetters.join(" "),
        }
      )
    }

    return buttonTheme;
  }

  const onCorrectLetter = letterLower => {
    const letter = letterLower.toUpperCase();
    setCorrectLetters([...correctLetters, letter]);
    setIncorrectLetters([...incorrectLetters.filter(i => i !== letter)]);
  }

  const onIncorrectLetter = letterLower => {
    const letter = letterLower.toUpperCase();
    setIncorrectLetters([...incorrectLetters, letter]);
    setCorrectLetters([...correctLetters.filter(i => i !== letter)]);
  }

  const onKeyPress = letter => {
    if (letter === "☕️") {
      window.open("http://2spacemilk.com", "_blank");
    } else letterCheck(letter.toLowerCase());
  };

  const letterCheck = letter => {
    // checks if letter has already been entered
    if (!letters.includes(letter)) {
      dispatch({ type: "ADD_LETTER", letter });
      const re = new RegExp(`${letter}`, "gi");

      if (re.test(data.title)) {
        // "tries" remains same if letter is in title
        onCorrectLetter(letter);

        dispatch({ type: "CORRECT_GUESS", letter });
      } else {
        onIncorrectLetter(letter);

        // tries-- if letter is not in title
        dispatch({ type: "DECREMENT_TRIES" });
      }
    }
  };

  return (
    <div>
      <Title />

      {/* <p>{data?.title}</p> */}
      <p>{data?.plot}</p>
      <p>Actors: {data?.actors}</p>
      <p>Director: {data?.director}</p>
      <p style={{ color: "rgba(0,0,0,.3)" }}>dev use: {data?.imdbID}</p>

      {isMobile && (
        <Keyboard
          keyboardRef={r => (keyboard.current = r)}
          layoutName={layout}
          onKeyPress={onKeyPress}
          theme={"hg-theme-default hg-layout-default myTheme"}
          layout={{
            default: [
              "Q W E R T Y U I O P",
              "A S D F G H J K L",
              "Z X C V B N M ☕️",
            ],
          }}
          buttonTheme={getButtonTheme()}
          className='pin-bottom'
        />
      )}

      <KeyboardEventHandler
        handleKeys={[..."qwertyuiopasdfghjklzxcvbnm"]}
        onKeyEvent={letter => letterCheck(letter)}
      />
    </div>
  );
}

export default Movie;

You can compare it with the commit you mentioned earlier: https://github.com/superhackerboy/hollywood-hangman/blob/1eef1123aea98f1c4adb90293fe3e12835cfd6d4/src/components/Movie.js#L17

Regards, Francisco Hodge

harlessmark commented 4 years ago

Thank you!!