From e10ec7883a8e0ac9808d47c59db68e795d0e482e Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 27 Sep 2023 20:16:21 +0100 Subject: [PATCH 1/6] Expose API via useImperativeHandle. --- src/index.tsx | 88 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 317e5f6..e8358f3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,44 +1,66 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { Chessground as ChessgroundApi } from 'chessground'; +import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { Api } from 'chessground/api'; +import { Chessground as ChessgroundApi } from 'chessground'; import { Config } from 'chessground/config'; +import { Api } from 'chessground/api'; +import { Key } from 'chessground/types'; + +export type LongAlgebraicMove = `${Key}${Key}` interface Props { - width?: number - height?: number + width?: number; + height?: number; contained?: boolean; - config?: Config + config?: Config; } -function Chessground({ - width = 900, height = 900, config = {}, contained = false, -}: Props) { - const [api, setApi] = useState(null); - - const ref = useRef(null); - - useEffect(() => { - if (ref && ref.current && !api) { - const chessgroundApi = ChessgroundApi(ref.current, { - animation: { enabled: true, duration: 200 }, - ...config, - }); - setApi(chessgroundApi); - } else if (ref && ref.current && api) { - api.set(config); +export interface ApiRef { + move: (moveStr: LongAlgebraicMove) => void; +} + +const Chessground = forwardRef( + ( + { width = 900, height = 900, config = {}, contained = false }: Props, + apiRef, + ) => { + const [api, setApi] = useState(null); + const divRef = useRef(null); + + const publicApi: ApiRef = { + move(moveStr: LongAlgebraicMove) { + console.log("[MOVE]", moveStr) + api!.move(moveStr.substring(0, 2) as Key, moveStr.substring(2,4) as Key) + } } - }, [ref]); - useEffect(() => { - api?.set(config); - }, [api, config]); + useImperativeHandle(apiRef, () => { + return publicApi; + }, [publicApi]); - return ( -
-
-
- ); -} + useEffect(() => { + if (divRef.current && !api) { + const chessgroundApi = ChessgroundApi(divRef.current, { + animation: { enabled: true, duration: 200 }, + ...config, + }); + setApi(chessgroundApi); + } else if (divRef.current && api) { + api.set(config); + } + }, [divRef.current, api]); + + useEffect(() => { + if (api) { + api.set(config); + } + }, [config]); + + return ( +
+
+
+ ); + } +); -export default Chessground; +export default Chessground; \ No newline at end of file From 133f0563f915ac717da8f2ca1470fb8f93ba5282 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 28 Sep 2023 21:36:49 +0100 Subject: [PATCH 2/6] return api instead of a subset publicApi. Return base types used in that api. --- src/index.tsx | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index e8358f3..f9cca5d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,37 +5,25 @@ import { Config } from 'chessground/config'; import { Api } from 'chessground/api'; import { Key } from 'chessground/types'; -export type LongAlgebraicMove = `${Key}${Key}` interface Props { width?: number; height?: number; contained?: boolean; config?: Config; -} +}; -export interface ApiRef { - move: (moveStr: LongAlgebraicMove) => void; -} - -const Chessground = forwardRef( +const Chessground = forwardRef( ( { width = 900, height = 900, config = {}, contained = false }: Props, apiRef, ) => { - const [api, setApi] = useState(null); + const [api, setApi] = useState(); const divRef = useRef(null); - const publicApi: ApiRef = { - move(moveStr: LongAlgebraicMove) { - console.log("[MOVE]", moveStr) - api!.move(moveStr.substring(0, 2) as Key, moveStr.substring(2,4) as Key) - } - } - useImperativeHandle(apiRef, () => { - return publicApi; - }, [publicApi]); + return api; + }, [api]); useEffect(() => { if (divRef.current && !api) { @@ -63,4 +51,5 @@ const Chessground = forwardRef( } ); +export type { Api, Config, Key }; export default Chessground; \ No newline at end of file From 91faf05b8796d0a658b656b810d06cc56b3ad893 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 28 Sep 2023 21:52:18 +0100 Subject: [PATCH 3/6] Update README with api example. --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/README.md b/README.md index d5e7eaa..7d82bfd 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ After installing, the component can be default imported and it has 4 optional pr - `contained: boolean` defaults to `false`, when enabled renders the chessboard in a `100%` width & height div. +- `ref: Api` returns an instance of the Chessground API for interacting with the chessboard. + Renders a simple `900 x 900` board, with pieces in their default position: ```jsx @@ -40,3 +42,51 @@ import "chessground/assets/chessground.cburnett.css"; ReactDOM.render(, document.getElementById("root")); ``` + +## Example: showing the moves of a game + +```tsx +import { useEffect, useRef } from "react"; +import Chessground, { Api, Config, Key } from "@react-chess/chessground"; + +// these styles must be imported somewhere +import "chessground/assets/chessground.base.css"; +import "chessground/assets/chessground.brown.css"; +import "chessground/assets/chessground.cburnett.css"; + +const CONFIG: Config = { + movable: { free: false }, +}; + +// Demo game moves in long algebraic form +const MOVES = ( + "e2e4 e7e5 g1f3 d7d6 d2d4 c8g4 d4e5 g4f3 d1f3 d6e5 " + + "f1c4 g8f6 f3b3 d8e7 b1c3 c7c6 c1g5 b7b5 c3b5 c6b5 " + + "c4b5 b8d7 e1c1 a8d8 d1d7 d8d7 h1d1 e7e6 b5d7 f6d7 " + + "b3b8 d7b8 d1d8" +).split(" "); + +export const DemoGameMoves = () => { + const apiRef = useRef(); + + useEffect(() => { + // Make a move every 2 seconds + const interval = setInterval(() => { + const move = MOVES.shift(); + if (move) { + apiRef.current!.move(move.substring(0,2) as Key, move.substring(2,4) as Key); + } else { + clearInterval(interval); + } + }, 2000); + return () => clearInterval(interval); + }); + + return ( + + ); +} +``` \ No newline at end of file From 879341cd6233852cacb3ed4c4bf75b6390cc0423 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 29 Sep 2023 20:25:53 +0100 Subject: [PATCH 4/6] Remove the animation default settings. --- src/index.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index f9cca5d..3b5cc5e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -27,10 +27,7 @@ const Chessground = forwardRef( useEffect(() => { if (divRef.current && !api) { - const chessgroundApi = ChessgroundApi(divRef.current, { - animation: { enabled: true, duration: 200 }, - ...config, - }); + const chessgroundApi = ChessgroundApi(divRef.current, config); setApi(chessgroundApi); } else if (divRef.current && api) { api.set(config); From 4a61870ccb419f7e9b85a03b26c3299ffdc82751 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 30 Sep 2023 10:22:34 +0100 Subject: [PATCH 5/6] Remove redundant config setting. --- src/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 3b5cc5e..94246ff 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -29,8 +29,6 @@ const Chessground = forwardRef( if (divRef.current && !api) { const chessgroundApi = ChessgroundApi(divRef.current, config); setApi(chessgroundApi); - } else if (divRef.current && api) { - api.set(config); } }, [divRef.current, api]); @@ -49,4 +47,4 @@ const Chessground = forwardRef( ); export type { Api, Config, Key }; -export default Chessground; \ No newline at end of file +export default Chessground; From 6879ec8f78450890e09adf31676171ebd245b698 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 30 Sep 2023 11:54:13 +0100 Subject: [PATCH 6/6] correct number of props to 5. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d82bfd..afa7ea7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ yarn add @react-chess/chessground ## Documentation -After installing, the component can be default imported and it has 4 optional props: +After installing, the component can be default imported and it has 5 optional props: - `width: number` defaults to `900`, determines width of the chessboard in pxs