@react-chess-tools/react-chess-puzzle 0.6.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/index.cjs +510 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +116 -0
- package/dist/index.d.ts +116 -0
- package/dist/{index.mjs → index.js} +76 -28
- package/dist/index.js.map +1 -0
- package/package.json +18 -9
- package/src/components/ChessPuzzle/ThemePuzzle.stories.tsx +300 -0
- package/src/components/ChessPuzzle/parts/PuzzleBoard.tsx +7 -2
- package/src/components/ChessPuzzle/parts/Root.tsx +27 -5
- package/src/docs/Theming.mdx +255 -0
- package/src/index.ts +14 -0
- package/src/theme/__tests__/context.test.tsx +66 -0
- package/src/theme/__tests__/defaults.test.ts +48 -0
- package/src/theme/__tests__/utils.test.ts +76 -0
- package/src/theme/context.tsx +36 -0
- package/src/theme/defaults.ts +16 -0
- package/src/theme/index.ts +20 -0
- package/src/theme/types.ts +29 -0
- package/src/theme/utils.ts +28 -0
- package/src/utils/index.ts +21 -11
- package/dist/index.d.mts +0 -57
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { renderHook } from "@testing-library/react";
|
|
3
|
+
import { useChessPuzzleTheme, PuzzleThemeProvider } from "../context";
|
|
4
|
+
import { defaultPuzzleTheme } from "../defaults";
|
|
5
|
+
|
|
6
|
+
describe("useChessPuzzleTheme", () => {
|
|
7
|
+
it("should return default puzzle theme when no provider is present", () => {
|
|
8
|
+
const { result } = renderHook(() => useChessPuzzleTheme());
|
|
9
|
+
expect(result.current).toEqual(defaultPuzzleTheme);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should return provided theme when wrapped in PuzzleThemeProvider", () => {
|
|
13
|
+
const customTheme = {
|
|
14
|
+
...defaultPuzzleTheme,
|
|
15
|
+
puzzle: {
|
|
16
|
+
...defaultPuzzleTheme.puzzle,
|
|
17
|
+
hint: "rgba(0, 255, 255, 0.5)",
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
22
|
+
<PuzzleThemeProvider theme={customTheme}>{children}</PuzzleThemeProvider>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const { result } = renderHook(() => useChessPuzzleTheme(), { wrapper });
|
|
26
|
+
expect(result.current.puzzle.hint).toBe("rgba(0, 255, 255, 0.5)");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return all puzzle-specific properties", () => {
|
|
30
|
+
const { result } = renderHook(() => useChessPuzzleTheme());
|
|
31
|
+
|
|
32
|
+
expect(result.current.puzzle).toHaveProperty("success");
|
|
33
|
+
expect(result.current.puzzle).toHaveProperty("failure");
|
|
34
|
+
expect(result.current.puzzle).toHaveProperty("hint");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should return inherited game theme properties", () => {
|
|
38
|
+
const { result } = renderHook(() => useChessPuzzleTheme());
|
|
39
|
+
|
|
40
|
+
expect(result.current.board).toBeDefined();
|
|
41
|
+
expect(result.current.state).toBeDefined();
|
|
42
|
+
expect(result.current.indicators).toBeDefined();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("PuzzleThemeProvider", () => {
|
|
47
|
+
it("should allow nested providers with inner provider winning", () => {
|
|
48
|
+
const outerTheme = {
|
|
49
|
+
...defaultPuzzleTheme,
|
|
50
|
+
puzzle: { ...defaultPuzzleTheme.puzzle, hint: "outer" },
|
|
51
|
+
};
|
|
52
|
+
const innerTheme = {
|
|
53
|
+
...defaultPuzzleTheme,
|
|
54
|
+
puzzle: { ...defaultPuzzleTheme.puzzle, hint: "inner" },
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
58
|
+
<PuzzleThemeProvider theme={outerTheme}>
|
|
59
|
+
<PuzzleThemeProvider theme={innerTheme}>{children}</PuzzleThemeProvider>
|
|
60
|
+
</PuzzleThemeProvider>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const { result } = renderHook(() => useChessPuzzleTheme(), { wrapper });
|
|
64
|
+
expect(result.current.puzzle.hint).toBe("inner");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { defaultPuzzleTheme } from "../defaults";
|
|
2
|
+
import { defaultGameTheme } from "@react-chess-tools/react-chess-game";
|
|
3
|
+
|
|
4
|
+
describe("defaultPuzzleTheme", () => {
|
|
5
|
+
describe("backward compatibility", () => {
|
|
6
|
+
it("should have the original success color", () => {
|
|
7
|
+
expect(defaultPuzzleTheme.puzzle.success).toBe("rgba(172, 206, 89, 0.5)");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should have the original failure color", () => {
|
|
11
|
+
expect(defaultPuzzleTheme.puzzle.failure).toBe("rgba(201, 52, 48, 0.5)");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should have the original hint color", () => {
|
|
15
|
+
expect(defaultPuzzleTheme.puzzle.hint).toBe("rgba(27, 172, 166, 0.5)");
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("inheritance from game theme", () => {
|
|
20
|
+
it("should include all game theme properties", () => {
|
|
21
|
+
expect(defaultPuzzleTheme.board).toBeDefined();
|
|
22
|
+
expect(defaultPuzzleTheme.state).toBeDefined();
|
|
23
|
+
expect(defaultPuzzleTheme.indicators).toBeDefined();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should have the same board colors as game theme", () => {
|
|
27
|
+
expect(defaultPuzzleTheme.board).toEqual(defaultGameTheme.board);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should have the same state colors as game theme", () => {
|
|
31
|
+
expect(defaultPuzzleTheme.state).toEqual(defaultGameTheme.state);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should have the same indicator colors as game theme", () => {
|
|
35
|
+
expect(defaultPuzzleTheme.indicators).toEqual(
|
|
36
|
+
defaultGameTheme.indicators,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("structure", () => {
|
|
42
|
+
it("should have puzzle property with all required colors", () => {
|
|
43
|
+
expect(defaultPuzzleTheme.puzzle).toHaveProperty("success");
|
|
44
|
+
expect(defaultPuzzleTheme.puzzle).toHaveProperty("failure");
|
|
45
|
+
expect(defaultPuzzleTheme.puzzle).toHaveProperty("hint");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { mergePuzzleTheme } from "../utils";
|
|
2
|
+
import { defaultPuzzleTheme } from "../defaults";
|
|
3
|
+
|
|
4
|
+
describe("mergePuzzleTheme", () => {
|
|
5
|
+
it("should return default puzzle theme when no partial theme is provided", () => {
|
|
6
|
+
const result = mergePuzzleTheme();
|
|
7
|
+
expect(result).toEqual(defaultPuzzleTheme);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should return default puzzle theme when undefined is provided", () => {
|
|
11
|
+
const result = mergePuzzleTheme(undefined);
|
|
12
|
+
expect(result).toEqual(defaultPuzzleTheme);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should return a new object, not a reference to default", () => {
|
|
16
|
+
const result = mergePuzzleTheme();
|
|
17
|
+
expect(result).not.toBe(defaultPuzzleTheme);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should override puzzle-specific colors", () => {
|
|
21
|
+
const result = mergePuzzleTheme({
|
|
22
|
+
puzzle: { hint: "rgba(0, 255, 255, 0.5)" },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
expect(result.puzzle.hint).toBe("rgba(0, 255, 255, 0.5)");
|
|
26
|
+
// Other puzzle colors should remain default
|
|
27
|
+
expect(result.puzzle.success).toBe(defaultPuzzleTheme.puzzle.success);
|
|
28
|
+
expect(result.puzzle.failure).toBe(defaultPuzzleTheme.puzzle.failure);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should override all puzzle colors at once", () => {
|
|
32
|
+
const result = mergePuzzleTheme({
|
|
33
|
+
puzzle: {
|
|
34
|
+
success: "rgba(0, 255, 0, 0.5)",
|
|
35
|
+
failure: "rgba(255, 0, 0, 0.5)",
|
|
36
|
+
hint: "rgba(0, 0, 255, 0.5)",
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(result.puzzle.success).toBe("rgba(0, 255, 0, 0.5)");
|
|
41
|
+
expect(result.puzzle.failure).toBe("rgba(255, 0, 0, 0.5)");
|
|
42
|
+
expect(result.puzzle.hint).toBe("rgba(0, 0, 255, 0.5)");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should override inherited game theme properties", () => {
|
|
46
|
+
const result = mergePuzzleTheme({
|
|
47
|
+
state: { lastMove: "rgba(100, 200, 100, 0.6)" },
|
|
48
|
+
board: { lightSquare: { backgroundColor: "#ffffff" } },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(result.state.lastMove).toBe("rgba(100, 200, 100, 0.6)");
|
|
52
|
+
expect(result.board.lightSquare).toEqual({ backgroundColor: "#ffffff" });
|
|
53
|
+
// Puzzle colors should remain default
|
|
54
|
+
expect(result.puzzle).toEqual(defaultPuzzleTheme.puzzle);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should allow overriding both game and puzzle properties", () => {
|
|
58
|
+
const result = mergePuzzleTheme({
|
|
59
|
+
state: { check: "rgba(255, 100, 100, 0.8)" },
|
|
60
|
+
puzzle: { success: "rgba(100, 255, 100, 0.8)" },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(result.state.check).toBe("rgba(255, 100, 100, 0.8)");
|
|
64
|
+
expect(result.puzzle.success).toBe("rgba(100, 255, 100, 0.8)");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should preserve unmentioned theme properties", () => {
|
|
68
|
+
const result = mergePuzzleTheme({
|
|
69
|
+
puzzle: { hint: "rgba(0, 255, 255, 0.5)" },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(result.board).toEqual(defaultPuzzleTheme.board);
|
|
73
|
+
expect(result.state).toEqual(defaultPuzzleTheme.state);
|
|
74
|
+
expect(result.indicators).toEqual(defaultPuzzleTheme.indicators);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React, { createContext, useContext } from "react";
|
|
2
|
+
import type { ChessPuzzleTheme } from "./types";
|
|
3
|
+
import { defaultPuzzleTheme } from "./defaults";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Context for ChessPuzzle theme
|
|
7
|
+
*/
|
|
8
|
+
export const ChessPuzzleThemeContext =
|
|
9
|
+
createContext<ChessPuzzleTheme>(defaultPuzzleTheme);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook to access the current ChessPuzzle theme.
|
|
13
|
+
* Returns the default puzzle theme if no ThemeProvider is present.
|
|
14
|
+
*/
|
|
15
|
+
export const useChessPuzzleTheme = (): ChessPuzzleTheme => {
|
|
16
|
+
return useContext(ChessPuzzleThemeContext);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface PuzzleThemeProviderProps {
|
|
20
|
+
theme: ChessPuzzleTheme;
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Internal provider component used by Puzzle Root when a theme prop is provided.
|
|
26
|
+
*/
|
|
27
|
+
export const PuzzleThemeProvider: React.FC<PuzzleThemeProviderProps> = ({
|
|
28
|
+
theme,
|
|
29
|
+
children,
|
|
30
|
+
}) => {
|
|
31
|
+
return (
|
|
32
|
+
<ChessPuzzleThemeContext.Provider value={theme}>
|
|
33
|
+
{children}
|
|
34
|
+
</ChessPuzzleThemeContext.Provider>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defaultGameTheme } from "@react-chess-tools/react-chess-game";
|
|
2
|
+
import type { ChessPuzzleTheme } from "./types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Default theme for ChessPuzzle component.
|
|
6
|
+
* Extends the default game theme with puzzle-specific colors.
|
|
7
|
+
* These values match the original hardcoded colors for backward compatibility.
|
|
8
|
+
*/
|
|
9
|
+
export const defaultPuzzleTheme: ChessPuzzleTheme = {
|
|
10
|
+
...defaultGameTheme,
|
|
11
|
+
puzzle: {
|
|
12
|
+
success: "rgba(172, 206, 89, 0.5)",
|
|
13
|
+
failure: "rgba(201, 52, 48, 0.5)",
|
|
14
|
+
hint: "rgba(27, 172, 166, 0.5)",
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Types
|
|
2
|
+
export type {
|
|
3
|
+
ChessPuzzleTheme,
|
|
4
|
+
PuzzleStateTheme,
|
|
5
|
+
PartialChessPuzzleTheme,
|
|
6
|
+
} from "./types";
|
|
7
|
+
|
|
8
|
+
// Default theme
|
|
9
|
+
export { defaultPuzzleTheme } from "./defaults";
|
|
10
|
+
|
|
11
|
+
// Utilities
|
|
12
|
+
export { mergePuzzleTheme } from "./utils";
|
|
13
|
+
|
|
14
|
+
// Context and hook
|
|
15
|
+
export {
|
|
16
|
+
ChessPuzzleThemeContext,
|
|
17
|
+
useChessPuzzleTheme,
|
|
18
|
+
PuzzleThemeProvider,
|
|
19
|
+
} from "./context";
|
|
20
|
+
export type { PuzzleThemeProviderProps } from "./context";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ChessGameTheme,
|
|
3
|
+
DeepPartial,
|
|
4
|
+
} from "@react-chess-tools/react-chess-game";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Puzzle-specific state colors (RGBA color strings)
|
|
8
|
+
*/
|
|
9
|
+
export interface PuzzleStateTheme {
|
|
10
|
+
/** Background color for successful moves */
|
|
11
|
+
success: string;
|
|
12
|
+
/** Background color for failed moves */
|
|
13
|
+
failure: string;
|
|
14
|
+
/** Background color for hint squares */
|
|
15
|
+
hint: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Complete theme configuration for ChessPuzzle component.
|
|
20
|
+
* Extends ChessGameTheme with puzzle-specific colors.
|
|
21
|
+
*/
|
|
22
|
+
export interface ChessPuzzleTheme extends ChessGameTheme {
|
|
23
|
+
puzzle: PuzzleStateTheme;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Partial theme for puzzle customization - allows overriding only specific properties
|
|
28
|
+
*/
|
|
29
|
+
export type PartialChessPuzzleTheme = DeepPartial<ChessPuzzleTheme>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { merge } from "lodash";
|
|
2
|
+
import type { ChessPuzzleTheme, PartialChessPuzzleTheme } from "./types";
|
|
3
|
+
import { defaultPuzzleTheme } from "./defaults";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Deep merges a partial puzzle theme with the default puzzle theme.
|
|
7
|
+
* Allows users to override only specific theme properties while keeping defaults for the rest.
|
|
8
|
+
*
|
|
9
|
+
* @param partialTheme - Partial theme with only the properties to override
|
|
10
|
+
* @returns Complete puzzle theme with overridden properties merged with defaults
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const customTheme = mergePuzzleTheme({
|
|
15
|
+
* puzzle: { hint: "rgba(0, 255, 255, 0.5)" }
|
|
16
|
+
* });
|
|
17
|
+
* // Returns full puzzle theme with only hint color changed
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const mergePuzzleTheme = (
|
|
21
|
+
partialTheme?: PartialChessPuzzleTheme,
|
|
22
|
+
): ChessPuzzleTheme => {
|
|
23
|
+
if (!partialTheme) {
|
|
24
|
+
return { ...defaultPuzzleTheme };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return merge({}, defaultPuzzleTheme, partialTheme);
|
|
28
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type Color, Chess, Move } from "chess.js";
|
|
2
2
|
import React, { CSSProperties, ReactElement, ReactNode } from "react";
|
|
3
3
|
import _ from "lodash";
|
|
4
|
+
import type { ChessPuzzleTheme } from "../theme/types";
|
|
5
|
+
import { defaultPuzzleTheme } from "../theme/defaults";
|
|
4
6
|
|
|
5
7
|
export type Status = "not-started" | "in-progress" | "solved" | "failed";
|
|
6
8
|
|
|
@@ -13,10 +15,6 @@ export type Puzzle = {
|
|
|
13
15
|
makeFirstMove?: boolean;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
|
-
const FAIL_COLOR = "rgba(201, 52, 48, 0.5)";
|
|
17
|
-
const SUCCESS_COLOR = "rgba(172, 206, 89, 0.5)";
|
|
18
|
-
const HINT_COLOR = "rgba(27, 172, 166, 0.5)";
|
|
19
|
-
|
|
20
18
|
export const getOrientation = (puzzle: Puzzle): Color => {
|
|
21
19
|
const fen = puzzle.fen;
|
|
22
20
|
const game = new Chess(fen);
|
|
@@ -36,12 +34,24 @@ export const isClickableElement = (
|
|
|
36
34
|
element: ReactNode,
|
|
37
35
|
): element is ClickableElement => React.isValidElement(element);
|
|
38
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Generates custom square styles for puzzle states based on theme.
|
|
39
|
+
*
|
|
40
|
+
* @param status - Current puzzle status
|
|
41
|
+
* @param hint - Current hint level
|
|
42
|
+
* @param isPlayerTurn - Whether it's the player's turn
|
|
43
|
+
* @param game - Chess.js game instance
|
|
44
|
+
* @param nextMove - The next expected move (for hints)
|
|
45
|
+
* @param theme - Theme configuration (defaults to defaultPuzzleTheme)
|
|
46
|
+
* @returns Record of square names to CSS properties
|
|
47
|
+
*/
|
|
39
48
|
export const getCustomSquareStyles = (
|
|
40
49
|
status: Status,
|
|
41
50
|
hint: Hint,
|
|
42
51
|
isPlayerTurn: boolean,
|
|
43
52
|
game: Chess,
|
|
44
53
|
nextMove?: Move | null,
|
|
54
|
+
theme: ChessPuzzleTheme = defaultPuzzleTheme,
|
|
45
55
|
) => {
|
|
46
56
|
const customSquareStyles: Record<string, CSSProperties> = {};
|
|
47
57
|
|
|
@@ -49,10 +59,10 @@ export const getCustomSquareStyles = (
|
|
|
49
59
|
|
|
50
60
|
if (status === "failed" && lastMove) {
|
|
51
61
|
customSquareStyles[lastMove.from] = {
|
|
52
|
-
backgroundColor:
|
|
62
|
+
backgroundColor: theme.puzzle.failure,
|
|
53
63
|
};
|
|
54
64
|
customSquareStyles[lastMove.to] = {
|
|
55
|
-
backgroundColor:
|
|
65
|
+
backgroundColor: theme.puzzle.failure,
|
|
56
66
|
};
|
|
57
67
|
}
|
|
58
68
|
|
|
@@ -61,17 +71,17 @@ export const getCustomSquareStyles = (
|
|
|
61
71
|
(status === "solved" || (status !== "failed" && !isPlayerTurn))
|
|
62
72
|
) {
|
|
63
73
|
customSquareStyles[lastMove.from] = {
|
|
64
|
-
backgroundColor:
|
|
74
|
+
backgroundColor: theme.puzzle.success,
|
|
65
75
|
};
|
|
66
76
|
customSquareStyles[lastMove.to] = {
|
|
67
|
-
backgroundColor:
|
|
77
|
+
backgroundColor: theme.puzzle.success,
|
|
68
78
|
};
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
if (hint === "piece") {
|
|
72
82
|
if (nextMove) {
|
|
73
83
|
customSquareStyles[nextMove.from] = {
|
|
74
|
-
backgroundColor:
|
|
84
|
+
backgroundColor: theme.puzzle.hint,
|
|
75
85
|
};
|
|
76
86
|
}
|
|
77
87
|
}
|
|
@@ -79,10 +89,10 @@ export const getCustomSquareStyles = (
|
|
|
79
89
|
if (hint === "move") {
|
|
80
90
|
if (nextMove) {
|
|
81
91
|
customSquareStyles[nextMove.from] = {
|
|
82
|
-
backgroundColor:
|
|
92
|
+
backgroundColor: theme.puzzle.hint,
|
|
83
93
|
};
|
|
84
94
|
customSquareStyles[nextMove.to] = {
|
|
85
|
-
backgroundColor:
|
|
95
|
+
backgroundColor: theme.puzzle.hint,
|
|
86
96
|
};
|
|
87
97
|
}
|
|
88
98
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import React__default from 'react';
|
|
3
|
-
import { ChessGame } from '@react-chess-tools/react-chess-game';
|
|
4
|
-
|
|
5
|
-
type Status = "not-started" | "in-progress" | "solved" | "failed";
|
|
6
|
-
type Hint = "none" | "piece" | "move";
|
|
7
|
-
type Puzzle = {
|
|
8
|
-
fen: string;
|
|
9
|
-
moves: string[];
|
|
10
|
-
makeFirstMove?: boolean;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
interface HintProps {
|
|
14
|
-
asChild?: boolean;
|
|
15
|
-
showOn?: Status[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface ResetProps {
|
|
19
|
-
asChild?: boolean;
|
|
20
|
-
puzzle?: Puzzle;
|
|
21
|
-
onReset?: (puzzleContext: ChessPuzzleContextType) => void;
|
|
22
|
-
showOn?: Status[];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface PuzzleBoardProps extends React__default.ComponentProps<typeof ChessGame.Board> {
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type ChessPuzzleContextType = {
|
|
29
|
-
status: Status;
|
|
30
|
-
changePuzzle: (puzzle: Puzzle) => void;
|
|
31
|
-
resetPuzzle: () => void;
|
|
32
|
-
puzzle: Puzzle;
|
|
33
|
-
hint: Hint;
|
|
34
|
-
nextMove?: string | null;
|
|
35
|
-
isPlayerTurn: boolean;
|
|
36
|
-
onHint: () => void;
|
|
37
|
-
puzzleState: Status;
|
|
38
|
-
movesPlayed: number;
|
|
39
|
-
totalMoves: number;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
interface RootProps {
|
|
43
|
-
puzzle: Puzzle;
|
|
44
|
-
onSolve?: (puzzleContext: ChessPuzzleContextType) => void;
|
|
45
|
-
onFail?: (puzzleContext: ChessPuzzleContextType) => void;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
declare const ChessPuzzle: {
|
|
49
|
-
Root: React.FC<React.PropsWithChildren<RootProps>>;
|
|
50
|
-
Board: React.FC<PuzzleBoardProps>;
|
|
51
|
-
Reset: React.FC<React.PropsWithChildren<ResetProps>>;
|
|
52
|
-
Hint: React.FC<React.PropsWithChildren<HintProps>>;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
declare const useChessPuzzleContext: () => ChessPuzzleContextType;
|
|
56
|
-
|
|
57
|
-
export { ChessPuzzle, type ChessPuzzleContextType, type Hint, type HintProps, type Puzzle, type PuzzleBoardProps, type ResetProps, type RootProps, type Status, useChessPuzzleContext };
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ChessPuzzle/parts/Root.tsx","../src/utils/index.ts","../src/hooks/useChessPuzzle.ts","../src/hooks/reducer.ts","../src/hooks/useChessPuzzleContext.ts","../src/components/ChessPuzzle/parts/PuzzleBoard.tsx","../src/components/ChessPuzzle/parts/Reset.tsx","../src/components/ChessPuzzle/parts/Hint.tsx","../src/components/ChessPuzzle/index.ts"],"sourcesContent":["import React from \"react\";\nimport { Puzzle, getOrientation } from \"../../../utils\";\nimport {\n ChessPuzzleContextType,\n useChessPuzzle,\n} from \"../../../hooks/useChessPuzzle\";\nimport { ChessGame } from \"@react-chess-tools/react-chess-game\";\nimport { ChessPuzzleContext } from \"../../../hooks/useChessPuzzleContext\";\n\nexport interface RootProps {\n puzzle: Puzzle;\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void;\n onFail?: (puzzleContext: ChessPuzzleContextType) => void;\n}\n\nconst PuzzleRoot: React.FC<React.PropsWithChildren<RootProps>> = ({\n puzzle,\n onSolve,\n onFail,\n children,\n}) => {\n const context = useChessPuzzle(puzzle, onSolve, onFail);\n\n return (\n <ChessPuzzleContext.Provider value={context}>\n {children}\n </ChessPuzzleContext.Provider>\n );\n};\n\nexport const Root: React.FC<React.PropsWithChildren<RootProps>> = ({\n puzzle,\n onSolve,\n onFail,\n children,\n}) => {\n return (\n <ChessGame.Root fen={puzzle.fen} orientation={getOrientation(puzzle)}>\n <PuzzleRoot puzzle={puzzle} onSolve={onSolve} onFail={onFail}>\n {children}\n </PuzzleRoot>\n </ChessGame.Root>\n );\n};\n","import { type Color, Chess, Move } from \"chess.js\";\nimport React, { CSSProperties, ReactElement, ReactNode } from \"react\";\nimport _ from \"lodash\";\n\nexport type Status = \"not-started\" | \"in-progress\" | \"solved\" | \"failed\";\n\nexport type Hint = \"none\" | \"piece\" | \"move\";\n\nexport type Puzzle = {\n fen: string;\n moves: string[];\n // if the first move of the puzzle has to be made by the cpu, as in chess.com puzzles\n makeFirstMove?: boolean;\n};\n\nconst FAIL_COLOR = \"rgba(201, 52, 48, 0.5)\";\nconst SUCCESS_COLOR = \"rgba(172, 206, 89, 0.5)\";\nconst HINT_COLOR = \"rgba(27, 172, 166, 0.5)\";\n\nexport const getOrientation = (puzzle: Puzzle): Color => {\n const fen = puzzle.fen;\n const game = new Chess(fen);\n if (puzzle.makeFirstMove) {\n game.move(puzzle.moves[0]);\n }\n return game.turn();\n};\n\ninterface ClickableElement extends ReactElement {\n props: {\n onClick?: () => void;\n };\n}\n\nexport const isClickableElement = (\n element: ReactNode,\n): element is ClickableElement => React.isValidElement(element);\n\nexport const getCustomSquareStyles = (\n status: Status,\n hint: Hint,\n isPlayerTurn: boolean,\n game: Chess,\n nextMove?: Move | null,\n) => {\n const customSquareStyles: Record<string, CSSProperties> = {};\n\n const lastMove = _.last(game.history({ verbose: true }));\n\n if (status === \"failed\" && lastMove) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: FAIL_COLOR,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: FAIL_COLOR,\n };\n }\n\n if (\n lastMove &&\n (status === \"solved\" || (status !== \"failed\" && !isPlayerTurn))\n ) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: SUCCESS_COLOR,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: SUCCESS_COLOR,\n };\n }\n\n if (hint === \"piece\") {\n if (nextMove) {\n customSquareStyles[nextMove.from] = {\n backgroundColor: HINT_COLOR,\n };\n }\n }\n\n if (hint === \"move\") {\n if (nextMove) {\n customSquareStyles[nextMove.from] = {\n backgroundColor: HINT_COLOR,\n };\n customSquareStyles[nextMove.to] = {\n backgroundColor: HINT_COLOR,\n };\n }\n }\n\n return customSquareStyles;\n};\n\nexport const stringToMove = (game: Chess, move: string | null | undefined) => {\n const copy = new Chess(game.fen());\n if (move === null || move === undefined) {\n return null;\n }\n try {\n return copy.move(move);\n } catch (e) {\n return null;\n }\n};\n","import { useEffect, useReducer, useCallback, useMemo } from \"react\";\nimport { initializePuzzle, reducer } from \"./reducer\";\nimport { getOrientation, type Puzzle, type Hint, type Status } from \"../utils\";\nimport { useChessGameContext } from \"@react-chess-tools/react-chess-game\";\n\nexport type ChessPuzzleContextType = {\n status: Status;\n changePuzzle: (puzzle: Puzzle) => void;\n resetPuzzle: () => void;\n puzzle: Puzzle;\n hint: Hint;\n nextMove?: string | null;\n isPlayerTurn: boolean;\n onHint: () => void;\n puzzleState: Status;\n movesPlayed: number;\n totalMoves: number;\n};\n\nexport const useChessPuzzle = (\n puzzle: Puzzle,\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void,\n onFail?: (puzzleContext: ChessPuzzleContextType) => void,\n): ChessPuzzleContextType => {\n const gameContext = useChessGameContext();\n\n const [state, dispatch] = useReducer(reducer, { puzzle }, initializePuzzle);\n\n const {\n game,\n methods: { makeMove, setPosition },\n } = gameContext;\n\n const changePuzzle = useCallback(\n (puzzle: Puzzle) => {\n setPosition(puzzle.fen, getOrientation(puzzle));\n dispatch({ type: \"INITIALIZE\", payload: { puzzle } });\n },\n [setPosition],\n );\n\n useEffect(() => {\n changePuzzle(puzzle);\n }, [JSON.stringify(puzzle), changePuzzle]);\n\n useEffect(() => {\n if (gameContext && game.fen() === puzzle.fen && state.needCpuMove) {\n setTimeout(\n () =>\n dispatch({\n type: \"CPU_MOVE\",\n }),\n 0,\n );\n }\n }, [gameContext, state.needCpuMove]);\n\n useEffect(() => {\n if (state.cpuMove) {\n makeMove(state.cpuMove);\n }\n }, [state.cpuMove]);\n\n if (!gameContext) {\n throw new Error(\"useChessPuzzle must be used within a ChessGameContext\");\n }\n\n const onHint = useCallback(() => {\n dispatch({ type: \"TOGGLE_HINT\" });\n }, []);\n\n const resetPuzzle = useCallback(() => {\n changePuzzle(puzzle);\n }, [changePuzzle, puzzle]);\n\n const puzzleContext: ChessPuzzleContextType = useMemo(\n () => ({\n status: state.status,\n changePuzzle,\n resetPuzzle,\n puzzle,\n hint: state.hint,\n onHint,\n nextMove: state.nextMove,\n isPlayerTurn: state.isPlayerTurn,\n puzzleState: state.status,\n movesPlayed: state.currentMoveIndex,\n totalMoves: puzzle.moves.length,\n }),\n [\n state.status,\n changePuzzle,\n resetPuzzle,\n puzzle,\n state.hint,\n onHint,\n state.nextMove,\n state.isPlayerTurn,\n state.currentMoveIndex,\n ],\n );\n\n useEffect(() => {\n if (game?.history()?.length <= 0 + (puzzle.makeFirstMove ? 1 : 0)) {\n return;\n }\n if (game.history().length % 2 === (puzzle.makeFirstMove ? 0 : 1)) {\n dispatch({\n type: \"PLAYER_MOVE\",\n payload: {\n move: gameContext?.game?.history({ verbose: true })?.pop() ?? null,\n puzzleContext,\n game: game,\n },\n });\n\n dispatch({\n type: \"CPU_MOVE\",\n });\n }\n }, [game?.history()?.length]);\n\n useEffect(() => {\n if (state.status === \"solved\" && !state.onSolveInvoked && onSolve) {\n onSolve(puzzleContext);\n dispatch({ type: \"MARK_SOLVE_INVOKED\" });\n }\n }, [state.status, state.onSolveInvoked]);\n\n useEffect(() => {\n if (state.status === \"failed\" && !state.onFailInvoked && onFail) {\n onFail(puzzleContext);\n dispatch({ type: \"MARK_FAIL_INVOKED\" });\n }\n }, [state.status, state.onFailInvoked]);\n\n return puzzleContext;\n};\n","import { Chess, Move } from \"chess.js\";\nimport { type Puzzle, type Hint, type Status } from \"../utils\";\nimport { ChessPuzzleContextType } from \"./useChessPuzzle\";\n\nexport type State = {\n puzzle: Puzzle;\n currentMoveIndex: number;\n status: Status;\n cpuMove?: string | null;\n nextMove?: string | null;\n hint: Hint;\n needCpuMove: boolean;\n isPlayerTurn: boolean;\n onSolveInvoked: boolean;\n onFailInvoked: boolean;\n};\n\nexport type Action =\n | {\n type: \"INITIALIZE\";\n payload: {\n puzzle: Puzzle;\n };\n }\n | {\n type: \"RESET\";\n }\n | { type: \"TOGGLE_HINT\" }\n | {\n type: \"CPU_MOVE\";\n }\n | {\n type: \"PLAYER_MOVE\";\n payload: {\n move?: Move | null;\n puzzleContext: ChessPuzzleContextType;\n game: Chess;\n };\n }\n | { type: \"MARK_SOLVE_INVOKED\" }\n | { type: \"MARK_FAIL_INVOKED\" };\n\nexport const initializePuzzle = ({ puzzle }: { puzzle: Puzzle }): State => {\n return {\n puzzle,\n currentMoveIndex: 0,\n status: \"not-started\",\n nextMove: puzzle.moves[0],\n hint: \"none\",\n cpuMove: null,\n needCpuMove: !!puzzle.makeFirstMove,\n isPlayerTurn: !puzzle.makeFirstMove,\n onSolveInvoked: false,\n onFailInvoked: false,\n };\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"INITIALIZE\":\n return {\n ...state,\n ...initializePuzzle(action.payload),\n };\n case \"RESET\":\n return {\n ...state,\n ...initializePuzzle({\n puzzle: state.puzzle,\n }),\n };\n case \"TOGGLE_HINT\":\n if (state.hint === \"none\") {\n return { ...state, hint: \"piece\" };\n }\n return { ...state, hint: \"move\" };\n case \"CPU_MOVE\":\n if (state.isPlayerTurn) {\n return state;\n }\n if ([\"solved\", \"failed\"].includes(state.status)) {\n return state;\n }\n\n return {\n ...state,\n currentMoveIndex: state.currentMoveIndex + 1,\n cpuMove: state.puzzle.moves[state.currentMoveIndex],\n nextMove:\n state.currentMoveIndex < state.puzzle.moves.length - 1\n ? state.puzzle.moves[state.currentMoveIndex + 1]\n : null,\n needCpuMove: false,\n isPlayerTurn: true,\n status: \"in-progress\",\n };\n\n case \"PLAYER_MOVE\": {\n const { move } = action.payload;\n\n const isMoveRight = [move?.san, move?.lan].includes(\n state?.nextMove || \"\",\n );\n const isPuzzleSolved =\n state.currentMoveIndex === state.puzzle.moves.length - 1;\n\n if (!isMoveRight) {\n return {\n ...state,\n status: \"failed\",\n nextMove: null,\n hint: \"none\",\n isPlayerTurn: false,\n onFailInvoked: false,\n };\n }\n\n if (isPuzzleSolved) {\n return {\n ...state,\n status: \"solved\",\n nextMove: null,\n hint: \"none\",\n isPlayerTurn: false,\n onSolveInvoked: false,\n };\n }\n\n return {\n ...state,\n hint: \"none\",\n currentMoveIndex: state.currentMoveIndex + 1,\n nextMove: state.puzzle.moves[state.currentMoveIndex + 1],\n status: \"in-progress\",\n needCpuMove: true,\n isPlayerTurn: false,\n };\n }\n\n case \"MARK_SOLVE_INVOKED\":\n return {\n ...state,\n onSolveInvoked: true,\n };\n\n case \"MARK_FAIL_INVOKED\":\n return {\n ...state,\n onFailInvoked: true,\n };\n\n default:\n return state;\n }\n};\n","import React from \"react\";\nimport { useChessPuzzle } from \"./useChessPuzzle\";\n\nexport const ChessPuzzleContext = React.createContext<ReturnType<\n typeof useChessPuzzle\n> | null>(null);\n\nexport const useChessPuzzleContext = () => {\n const context = React.useContext(ChessPuzzleContext);\n if (!context) {\n throw new Error(\n `useChessPuzzleContext must be used within a ChessPuzzle component. Make sure your component is wrapped with <ChessPuzzle.Root> or ensure the ChessPuzzle component is properly rendered in the component tree.`,\n );\n }\n return context;\n};\n","import React from \"react\";\nimport {\n ChessGame,\n deepMergeChessboardOptions,\n useChessGameContext,\n} from \"@react-chess-tools/react-chess-game\";\nimport { getCustomSquareStyles, stringToMove } from \"../../../utils\";\nimport { useChessPuzzleContext } from \"../../..\";\n\nexport interface PuzzleBoardProps\n extends React.ComponentProps<typeof ChessGame.Board> {}\nexport const PuzzleBoard: React.FC<PuzzleBoardProps> = ({\n options = {},\n ...rest\n}) => {\n const puzzleContext = useChessPuzzleContext();\n const gameContext = useChessGameContext();\n\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n\n const { game } = gameContext;\n const { status, hint, isPlayerTurn, nextMove } = puzzleContext;\n\n const mergedOptions = deepMergeChessboardOptions(options, {\n squareStyles: getCustomSquareStyles(\n status,\n hint,\n isPlayerTurn,\n game,\n stringToMove(game, nextMove),\n ),\n });\n\n return <ChessGame.Board {...rest} options={mergedOptions} />;\n};\n","import React from \"react\";\nimport { isClickableElement, type Puzzle, type Status } from \"../../../utils\";\nimport { useChessPuzzleContext, type ChessPuzzleContextType } from \"../../..\";\n\nexport interface ResetProps {\n asChild?: boolean;\n puzzle?: Puzzle;\n onReset?: (puzzleContext: ChessPuzzleContextType) => void;\n showOn?: Status[];\n}\n\nconst defaultShowOn: Status[] = [\"failed\", \"solved\"];\n\nexport const Reset: React.FC<React.PropsWithChildren<ResetProps>> = ({\n children,\n asChild,\n puzzle,\n onReset,\n showOn = defaultShowOn,\n}) => {\n const puzzleContext = useChessPuzzleContext();\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n const { changePuzzle, status } = puzzleContext;\n const handleClick = () => {\n changePuzzle(puzzle || puzzleContext.puzzle);\n onReset?.(puzzleContext);\n };\n\n if (!showOn.includes(status)) {\n return null;\n }\n\n if (asChild) {\n const child = React.Children.only(children);\n if (isClickableElement(child)) {\n return React.cloneElement(child, {\n onClick: handleClick,\n });\n } else {\n throw new Error(\"Change child must be a clickable element\");\n }\n }\n\n return (\n <button type=\"button\" onClick={handleClick}>\n {children}\n </button>\n );\n};\n","import React from \"react\";\nimport { Status, isClickableElement } from \"../../../utils\";\nimport { useChessPuzzleContext } from \"../../..\";\n\nexport interface HintProps {\n asChild?: boolean;\n showOn?: Status[];\n}\n\nconst defaultShowOn: Status[] = [\"not-started\", \"in-progress\"];\n\nexport const Hint: React.FC<React.PropsWithChildren<HintProps>> = ({\n children,\n asChild,\n showOn = defaultShowOn,\n}) => {\n const puzzleContext = useChessPuzzleContext();\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n const { onHint, status } = puzzleContext;\n const handleClick = () => {\n onHint();\n };\n\n if (!showOn.includes(status)) {\n return null;\n }\n\n if (asChild) {\n const child = React.Children.only(children);\n if (isClickableElement(child)) {\n return React.cloneElement(child, {\n onClick: handleClick,\n });\n } else {\n throw new Error(\"Change child must be a clickable element\");\n }\n }\n\n return (\n <button type=\"button\" onClick={handleClick}>\n {children}\n </button>\n );\n};\n","import { Root } from \"./parts/Root\";\nimport { PuzzleBoard } from \"./parts/PuzzleBoard\";\nimport { Reset } from \"./parts/Reset\";\nimport { Hint } from \"./parts/Hint\";\n\nexport const ChessPuzzle = {\n Root,\n Board: PuzzleBoard,\n Reset,\n Hint,\n};\n"],"mappings":"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","names":["React","puzzle","_a","React","React","React","ChessGame","useChessGameContext","useChessGameContext","React","ChessGame","React","React","React","defaultShowOn","React"]}
|