Build in basic drag & drop for tiles

This commit is contained in:
Joel Therrien 2023-08-07 22:56:12 -07:00
parent 44e3b97f14
commit 1fb5235f2b
2 changed files with 51 additions and 6 deletions

View file

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import {GameWasm, Letter as LetterData, Tray} from "word_grid"; import {GameWasm, Letter as LetterData, Tray} from "word_grid";
import {createRoot} from "react-dom/client"; import {createRoot} from "react-dom/client";
import {useReducer, useState} from "react"; import {Children, useReducer, useState} from "react";
export enum LocationType { export enum LocationType {
GRID, GRID,
@ -29,6 +29,8 @@ function matchCoordinate(playerLetters: PlayableLetterData[], coords: Coordinate
} }
type TileDispatch = React.Dispatch<{start: CoordinateData, end: CoordinateData}>;
function movePlayableLetters(playerLetters: PlayableLetterData[], update: {start: CoordinateData, end: CoordinateData}) { function movePlayableLetters(playerLetters: PlayableLetterData[], update: {start: CoordinateData, end: CoordinateData}) {
let startIndex = matchCoordinate(playerLetters, update.start); let startIndex = matchCoordinate(playerLetters, update.start);
@ -66,7 +68,7 @@ export function Game(props: {wasm: GameWasm}) {
return <> return <>
<TileTray letters={playerLetters} trayLength={7}/> <TileTray letters={playerLetters} trayLength={7} dispatch={dispatch}/>
<button onClick={(e) => { <button onClick={(e) => {
dispatch({ dispatch({
"start": { "start": {
@ -84,6 +86,32 @@ export function Game(props: {wasm: GameWasm}) {
} }
export function TileSlot(props: { tile: React.JSX.Element | undefined, location: CoordinateData, dispatch: TileDispatch }): React.JSX.Element {
let isDraggable = props.tile !== undefined;
function onDragStart(e: React.DragEvent<HTMLDivElement>) {
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("wordGrid/coords", JSON.stringify(props.location));
}
function onDrop(e: React.DragEvent<HTMLDivElement>) {
const startLocation: CoordinateData = JSON.parse(e.dataTransfer.getData("wordGrid/coords"));
const thisLocation = props.location;
props.dispatch({start: startLocation, end: thisLocation});
}
return <div className="tileSpot"
draggable={isDraggable}
onDragStart={onDragStart}
onDrop={onDrop}
onDragOver={(e) => {e.preventDefault()}}
>
{props.tile}
</div>
}
export function Letter(props: { data: LetterData }): React.JSX.Element { export function Letter(props: { data: LetterData }): React.JSX.Element {
return <div className="letter"> return <div className="letter">
<div className="text">{props.data.text}</div> <div className="text">{props.data.text}</div>
@ -92,18 +120,28 @@ export function Letter(props: { data: LetterData }): React.JSX.Element {
} }
export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength: number }): React.JSX.Element { export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength: number, dispatch: TileDispatch }): React.JSX.Element {
let elements: JSX.Element[] = []; let elements: JSX.Element[] = [];
for (let i=0; i<props.trayLength; i++) { for (let i=0; i<props.trayLength; i++) {
elements.push( elements.push(
<div key={"empty" + i}></div> <TileSlot
tile={undefined}
key={"empty" + i}
location={{location: LocationType.TRAY, index: i}}
dispatch={props.dispatch} />
); );
} }
for (let letter of props.letters) { for (let letter of props.letters) {
if (letter.location === LocationType.TRAY) { if (letter.location === LocationType.TRAY) {
elements[letter.index] = <Letter data={letter} key={"letter" + letter.index} /> elements[letter.index] =
<TileSlot
tile={<Letter data={letter} />}
key={"letter" + letter.index}
location={{location: LocationType.TRAY, index: letter.index}}
dispatch={props.dispatch} />
} }
} }

View file

@ -11,10 +11,17 @@
margin: 10px; margin: 10px;
} }
.tileSpot {
height: 100%;
width: 100%;
}
.letter { .letter {
background-color: #e5cca9; background-color: #e5cca9;
position: relative; // Used for the positioning of the sub-components
user-select: none; user-select: none;
height: 100%;
width: 100%;
position: relative; // Used for the positioning of the sub-components
.text { .text {
position: absolute; position: absolute;