react-native-chess-kit 0.4.2 → 0.5.1

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.
Files changed (82) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +168 -168
  3. package/lib/commonjs/board-annotations.js +8 -8
  4. package/lib/commonjs/board-arrows.js +7 -7
  5. package/lib/commonjs/board-background.js +5 -5
  6. package/lib/commonjs/board-coordinates.js +78 -11
  7. package/lib/commonjs/board-coordinates.js.map +1 -1
  8. package/lib/commonjs/board-drag-ghost.js +10 -10
  9. package/lib/commonjs/board-highlights.js +15 -15
  10. package/lib/commonjs/board-legal-dots.js +5 -5
  11. package/lib/commonjs/board-piece.js +25 -25
  12. package/lib/commonjs/board-pieces.js +6 -6
  13. package/lib/commonjs/board.js +76 -35
  14. package/lib/commonjs/board.js.map +1 -1
  15. package/lib/commonjs/constants.js +4 -1
  16. package/lib/commonjs/constants.js.map +1 -1
  17. package/lib/commonjs/index.js.map +1 -1
  18. package/lib/commonjs/promotion-picker.js +8 -8
  19. package/lib/commonjs/static-board.js +51 -16
  20. package/lib/commonjs/static-board.js.map +1 -1
  21. package/lib/commonjs/use-board-gesture.js +52 -33
  22. package/lib/commonjs/use-board-gesture.js.map +1 -1
  23. package/lib/commonjs/use-board-pieces.js +15 -15
  24. package/lib/commonjs/use-board-state.js +8 -8
  25. package/lib/commonjs/use-premove.js +12 -12
  26. package/lib/module/board-annotations.js +8 -8
  27. package/lib/module/board-arrows.js +7 -7
  28. package/lib/module/board-background.js +5 -5
  29. package/lib/module/board-coordinates.js +79 -12
  30. package/lib/module/board-coordinates.js.map +1 -1
  31. package/lib/module/board-drag-ghost.js +10 -10
  32. package/lib/module/board-highlights.js +15 -15
  33. package/lib/module/board-legal-dots.js +5 -5
  34. package/lib/module/board-piece.js +25 -25
  35. package/lib/module/board-pieces.js +6 -6
  36. package/lib/module/board.js +77 -36
  37. package/lib/module/board.js.map +1 -1
  38. package/lib/module/constants.js +3 -0
  39. package/lib/module/constants.js.map +1 -1
  40. package/lib/module/index.js.map +1 -1
  41. package/lib/module/promotion-picker.js +8 -8
  42. package/lib/module/static-board.js +52 -17
  43. package/lib/module/static-board.js.map +1 -1
  44. package/lib/module/use-board-gesture.js +52 -33
  45. package/lib/module/use-board-gesture.js.map +1 -1
  46. package/lib/module/use-board-pieces.js +15 -15
  47. package/lib/module/use-board-state.js +8 -8
  48. package/lib/module/use-premove.js +12 -12
  49. package/lib/typescript/board-coordinates.d.ts +10 -4
  50. package/lib/typescript/board-coordinates.d.ts.map +1 -1
  51. package/lib/typescript/board.d.ts.map +1 -1
  52. package/lib/typescript/constants.d.ts +2 -0
  53. package/lib/typescript/constants.d.ts.map +1 -1
  54. package/lib/typescript/index.d.ts +1 -1
  55. package/lib/typescript/index.d.ts.map +1 -1
  56. package/lib/typescript/static-board.d.ts.map +1 -1
  57. package/lib/typescript/types.d.ts +23 -3
  58. package/lib/typescript/types.d.ts.map +1 -1
  59. package/lib/typescript/use-board-gesture.d.ts.map +1 -1
  60. package/package.json +1 -1
  61. package/src/board-annotations.tsx +147 -147
  62. package/src/board-arrows.tsx +197 -197
  63. package/src/board-background.tsx +46 -46
  64. package/src/board-coordinates.tsx +192 -98
  65. package/src/board-drag-ghost.tsx +132 -132
  66. package/src/board-highlights.tsx +226 -226
  67. package/src/board-legal-dots.tsx +73 -73
  68. package/src/board-piece.tsx +160 -160
  69. package/src/board-pieces.tsx +63 -63
  70. package/src/board.tsx +685 -641
  71. package/src/constants.ts +103 -100
  72. package/src/index.ts +101 -100
  73. package/src/pieces/default-pieces.tsx +383 -383
  74. package/src/pieces/index.ts +1 -1
  75. package/src/promotion-picker.tsx +147 -147
  76. package/src/static-board.tsx +187 -150
  77. package/src/themes.ts +129 -129
  78. package/src/types.ts +373 -352
  79. package/src/use-board-gesture.ts +429 -412
  80. package/src/use-board-pieces.ts +158 -158
  81. package/src/use-board-state.ts +111 -111
  82. package/src/use-premove.ts +59 -59
@@ -1,160 +1,160 @@
1
- import React, { useEffect } from 'react';
2
- import Animated, {
3
- useAnimatedStyle,
4
- useSharedValue,
5
- withTiming,
6
- withSpring,
7
- type SharedValue,
8
- type BaseAnimationBuilder,
9
- } from 'react-native-reanimated';
10
-
11
- import type { AnimationConfig } from './types';
12
- import { DEFAULT_MOVE_DURATION } from './constants';
13
-
14
- type BoardPieceProps = {
15
- /** Target pixel position (top-left of destination square) */
16
- targetX: number;
17
- targetY: number;
18
- /** Square size in pixels */
19
- squareSize: number;
20
- /** Animation config for piece movement (timing or spring) */
21
- animationConfig?: AnimationConfig;
22
- /** Fallback move duration if animationConfig not provided */
23
- moveDuration?: number;
24
- /** The piece visual (rendered by parent via renderPiece) */
25
- children: React.ReactElement;
26
- /** Gesture state: is this piece currently being dragged? */
27
- activeSquare: SharedValue<string | null>;
28
- isDragging: SharedValue<boolean>;
29
- /** This piece's current square */
30
- square: string;
31
- /**
32
- * Exiting animation played when this piece unmounts (e.g. captured).
33
- * Pass `undefined` to disable (piece disappears instantly on unmount).
34
- */
35
- exitingAnimation?: BaseAnimationBuilder | typeof BaseAnimationBuilder;
36
- };
37
-
38
- /**
39
- * Animate a shared value using the provided AnimationConfig.
40
- * Falls back to withTiming with moveDuration for backwards compatibility.
41
- */
42
- function animateValue(
43
- target: number,
44
- config?: AnimationConfig,
45
- moveDuration?: number,
46
- ): number {
47
- if (config) {
48
- if (config.type === 'spring') {
49
- return withSpring(target, {
50
- damping: config.damping ?? 15,
51
- stiffness: config.stiffness ?? 200,
52
- mass: config.mass ?? 1,
53
- });
54
- }
55
- // timing
56
- return withTiming(target, {
57
- duration: config.duration ?? DEFAULT_MOVE_DURATION,
58
- });
59
- }
60
-
61
- const duration = moveDuration ?? DEFAULT_MOVE_DURATION;
62
- if (duration <= 0) return target;
63
- return withTiming(target, { duration });
64
- }
65
-
66
- /**
67
- * A single animated chess piece.
68
- *
69
- * Uses two nested Animated.Views to avoid the Reanimated warning
70
- * "Property opacity may be overwritten by a layout animation":
71
- *
72
- * Outer view: position (transform) + exiting layout animation (FadeOut)
73
- * Inner view: drag-hide opacity
74
- *
75
- * Only `transform` and `opacity` are animated — Reanimated's fast path
76
- * on Android. No layout properties (top/left/width/height), avoiding
77
- * costly layout recalculations on low-end devices.
78
- *
79
- * During drag:
80
- * - Inner view hides (opacity: 0) — the drag ghost shows instead
81
- *
82
- * After a move:
83
- * - Outer view snaps to new position via withTiming/withSpring
84
- *
85
- * On capture (unmount):
86
- * - Outer view plays the exitingAnimation (default: FadeOut, no conflict with inner opacity)
87
- * - Pass exitingAnimation={undefined} to disable (instant disappear on full board remount)
88
- */
89
- export const BoardPieceView = React.memo(
90
- function BoardPieceView({
91
- targetX,
92
- targetY,
93
- squareSize,
94
- animationConfig,
95
- moveDuration,
96
- children,
97
- activeSquare,
98
- isDragging,
99
- square,
100
- exitingAnimation,
101
- }: BoardPieceProps) {
102
- // Shared values for smooth animated position — written from JS, read on UI thread
103
- const currentX = useSharedValue(targetX);
104
- const currentY = useSharedValue(targetY);
105
-
106
- // When target position changes (piece moved), animate to the new square.
107
- // useEffect is the correct pattern for reacting to JS prop changes —
108
- // useDerivedValue is meant for shared-value-to-shared-value derivation.
109
- useEffect(() => {
110
- currentX.value = animateValue(targetX, animationConfig, moveDuration);
111
- currentY.value = animateValue(targetY, animationConfig, moveDuration);
112
- }, [targetX, targetY, animationConfig, moveDuration, currentX, currentY]);
113
-
114
- // Position style on outer view — no opacity here to avoid conflict
115
- // with the FadeOut exiting layout animation
116
- const positionStyle = useAnimatedStyle(() => ({
117
- transform: [
118
- { translateX: currentX.value },
119
- { translateY: currentY.value },
120
- ],
121
- }));
122
-
123
- // Drag-hide opacity on inner view — separate from the exiting animation
124
- const opacityStyle = useAnimatedStyle(() => {
125
- const isBeingDragged = isDragging.value && activeSquare.value === square;
126
- return { opacity: isBeingDragged ? 0 : 1 };
127
- });
128
-
129
- return (
130
- <Animated.View
131
- style={[
132
- {
133
- position: 'absolute',
134
- width: squareSize,
135
- height: squareSize,
136
- },
137
- positionStyle,
138
- ]}
139
- // Exiting animation when this piece is captured (removed from the piece list).
140
- // Lives on the outer view so it doesn't conflict with the
141
- // drag-hide opacity on the inner view.
142
- // Pass undefined to disable (e.g. during full board remount via key change).
143
- exiting={exitingAnimation}
144
- >
145
- <Animated.View style={[{ flex: 1 }, opacityStyle]}>
146
- {children}
147
- </Animated.View>
148
- </Animated.View>
149
- );
150
- },
151
- // Custom comparator: only re-render when position, square, or animation config changes
152
- (prev, next) =>
153
- prev.targetX === next.targetX &&
154
- prev.targetY === next.targetY &&
155
- prev.square === next.square &&
156
- prev.squareSize === next.squareSize &&
157
- prev.moveDuration === next.moveDuration &&
158
- prev.animationConfig === next.animationConfig &&
159
- prev.children === next.children,
160
- );
1
+ import React, { useEffect } from 'react';
2
+ import Animated, {
3
+ useAnimatedStyle,
4
+ useSharedValue,
5
+ withTiming,
6
+ withSpring,
7
+ type SharedValue,
8
+ type BaseAnimationBuilder,
9
+ } from 'react-native-reanimated';
10
+
11
+ import type { AnimationConfig } from './types';
12
+ import { DEFAULT_MOVE_DURATION } from './constants';
13
+
14
+ type BoardPieceProps = {
15
+ /** Target pixel position (top-left of destination square) */
16
+ targetX: number;
17
+ targetY: number;
18
+ /** Square size in pixels */
19
+ squareSize: number;
20
+ /** Animation config for piece movement (timing or spring) */
21
+ animationConfig?: AnimationConfig;
22
+ /** Fallback move duration if animationConfig not provided */
23
+ moveDuration?: number;
24
+ /** The piece visual (rendered by parent via renderPiece) */
25
+ children: React.ReactElement;
26
+ /** Gesture state: is this piece currently being dragged? */
27
+ activeSquare: SharedValue<string | null>;
28
+ isDragging: SharedValue<boolean>;
29
+ /** This piece's current square */
30
+ square: string;
31
+ /**
32
+ * Exiting animation played when this piece unmounts (e.g. captured).
33
+ * Pass `undefined` to disable (piece disappears instantly on unmount).
34
+ */
35
+ exitingAnimation?: BaseAnimationBuilder | typeof BaseAnimationBuilder;
36
+ };
37
+
38
+ /**
39
+ * Animate a shared value using the provided AnimationConfig.
40
+ * Falls back to withTiming with moveDuration for backwards compatibility.
41
+ */
42
+ function animateValue(
43
+ target: number,
44
+ config?: AnimationConfig,
45
+ moveDuration?: number,
46
+ ): number {
47
+ if (config) {
48
+ if (config.type === 'spring') {
49
+ return withSpring(target, {
50
+ damping: config.damping ?? 15,
51
+ stiffness: config.stiffness ?? 200,
52
+ mass: config.mass ?? 1,
53
+ });
54
+ }
55
+ // timing
56
+ return withTiming(target, {
57
+ duration: config.duration ?? DEFAULT_MOVE_DURATION,
58
+ });
59
+ }
60
+
61
+ const duration = moveDuration ?? DEFAULT_MOVE_DURATION;
62
+ if (duration <= 0) return target;
63
+ return withTiming(target, { duration });
64
+ }
65
+
66
+ /**
67
+ * A single animated chess piece.
68
+ *
69
+ * Uses two nested Animated.Views to avoid the Reanimated warning
70
+ * "Property opacity may be overwritten by a layout animation":
71
+ *
72
+ * Outer view: position (transform) + exiting layout animation (FadeOut)
73
+ * Inner view: drag-hide opacity
74
+ *
75
+ * Only `transform` and `opacity` are animated — Reanimated's fast path
76
+ * on Android. No layout properties (top/left/width/height), avoiding
77
+ * costly layout recalculations on low-end devices.
78
+ *
79
+ * During drag:
80
+ * - Inner view hides (opacity: 0) — the drag ghost shows instead
81
+ *
82
+ * After a move:
83
+ * - Outer view snaps to new position via withTiming/withSpring
84
+ *
85
+ * On capture (unmount):
86
+ * - Outer view plays the exitingAnimation (default: FadeOut, no conflict with inner opacity)
87
+ * - Pass exitingAnimation={undefined} to disable (instant disappear on full board remount)
88
+ */
89
+ export const BoardPieceView = React.memo(
90
+ function BoardPieceView({
91
+ targetX,
92
+ targetY,
93
+ squareSize,
94
+ animationConfig,
95
+ moveDuration,
96
+ children,
97
+ activeSquare,
98
+ isDragging,
99
+ square,
100
+ exitingAnimation,
101
+ }: BoardPieceProps) {
102
+ // Shared values for smooth animated position — written from JS, read on UI thread
103
+ const currentX = useSharedValue(targetX);
104
+ const currentY = useSharedValue(targetY);
105
+
106
+ // When target position changes (piece moved), animate to the new square.
107
+ // useEffect is the correct pattern for reacting to JS prop changes —
108
+ // useDerivedValue is meant for shared-value-to-shared-value derivation.
109
+ useEffect(() => {
110
+ currentX.value = animateValue(targetX, animationConfig, moveDuration);
111
+ currentY.value = animateValue(targetY, animationConfig, moveDuration);
112
+ }, [targetX, targetY, animationConfig, moveDuration, currentX, currentY]);
113
+
114
+ // Position style on outer view — no opacity here to avoid conflict
115
+ // with the FadeOut exiting layout animation
116
+ const positionStyle = useAnimatedStyle(() => ({
117
+ transform: [
118
+ { translateX: currentX.value },
119
+ { translateY: currentY.value },
120
+ ],
121
+ }));
122
+
123
+ // Drag-hide opacity on inner view — separate from the exiting animation
124
+ const opacityStyle = useAnimatedStyle(() => {
125
+ const isBeingDragged = isDragging.value && activeSquare.value === square;
126
+ return { opacity: isBeingDragged ? 0 : 1 };
127
+ });
128
+
129
+ return (
130
+ <Animated.View
131
+ style={[
132
+ {
133
+ position: 'absolute',
134
+ width: squareSize,
135
+ height: squareSize,
136
+ },
137
+ positionStyle,
138
+ ]}
139
+ // Exiting animation when this piece is captured (removed from the piece list).
140
+ // Lives on the outer view so it doesn't conflict with the
141
+ // drag-hide opacity on the inner view.
142
+ // Pass undefined to disable (e.g. during full board remount via key change).
143
+ exiting={exitingAnimation}
144
+ >
145
+ <Animated.View style={[{ flex: 1 }, opacityStyle]}>
146
+ {children}
147
+ </Animated.View>
148
+ </Animated.View>
149
+ );
150
+ },
151
+ // Custom comparator: only re-render when position, square, or animation config changes
152
+ (prev, next) =>
153
+ prev.targetX === next.targetX &&
154
+ prev.targetY === next.targetY &&
155
+ prev.square === next.square &&
156
+ prev.squareSize === next.squareSize &&
157
+ prev.moveDuration === next.moveDuration &&
158
+ prev.animationConfig === next.animationConfig &&
159
+ prev.children === next.children,
160
+ );
@@ -1,63 +1,63 @@
1
- import React from 'react';
2
- import type { SharedValue, BaseAnimationBuilder } from 'react-native-reanimated';
3
-
4
- import type { ChessColor, BoardPiece, AnimationConfig } from './types';
5
- import { BoardPieceView } from './board-piece';
6
- import { squareToXY } from './use-board-pieces';
7
-
8
- type BoardPiecesProps = {
9
- pieces: BoardPiece[];
10
- squareSize: number;
11
- orientation: ChessColor;
12
- moveDuration: number;
13
- animationConfig?: AnimationConfig;
14
- renderPiece: (code: string, size: number) => React.ReactElement;
15
- activeSquare: SharedValue<string | null>;
16
- isDragging: SharedValue<boolean>;
17
- /** Exiting animation for pieces. Passed through to each BoardPieceView. */
18
- exitingAnimation?: BaseAnimationBuilder | typeof BaseAnimationBuilder;
19
- };
20
-
21
- /**
22
- * Renders all pieces on the board.
23
- *
24
- * Each piece gets a stable key (from useBoardPieces) so React doesn't
25
- * unmount/remount pieces that moved — it updates their position props
26
- * and the BoardPieceView animates the transition.
27
- */
28
- export const BoardPiecesLayer = React.memo(function BoardPiecesLayer({
29
- pieces,
30
- squareSize,
31
- orientation,
32
- moveDuration,
33
- animationConfig,
34
- renderPiece,
35
- activeSquare,
36
- isDragging,
37
- exitingAnimation,
38
- }: BoardPiecesProps) {
39
- return (
40
- <>
41
- {pieces.map((piece) => {
42
- const { x, y } = squareToXY(piece.square, squareSize, orientation);
43
-
44
- return (
45
- <BoardPieceView
46
- key={piece.id}
47
- targetX={x}
48
- targetY={y}
49
- squareSize={squareSize}
50
- moveDuration={moveDuration}
51
- animationConfig={animationConfig}
52
- activeSquare={activeSquare}
53
- isDragging={isDragging}
54
- square={piece.square}
55
- exitingAnimation={exitingAnimation}
56
- >
57
- {renderPiece(piece.code, squareSize)}
58
- </BoardPieceView>
59
- );
60
- })}
61
- </>
62
- );
63
- });
1
+ import React from 'react';
2
+ import type { SharedValue, BaseAnimationBuilder } from 'react-native-reanimated';
3
+
4
+ import type { ChessColor, BoardPiece, AnimationConfig } from './types';
5
+ import { BoardPieceView } from './board-piece';
6
+ import { squareToXY } from './use-board-pieces';
7
+
8
+ type BoardPiecesProps = {
9
+ pieces: BoardPiece[];
10
+ squareSize: number;
11
+ orientation: ChessColor;
12
+ moveDuration: number;
13
+ animationConfig?: AnimationConfig;
14
+ renderPiece: (code: string, size: number) => React.ReactElement;
15
+ activeSquare: SharedValue<string | null>;
16
+ isDragging: SharedValue<boolean>;
17
+ /** Exiting animation for pieces. Passed through to each BoardPieceView. */
18
+ exitingAnimation?: BaseAnimationBuilder | typeof BaseAnimationBuilder;
19
+ };
20
+
21
+ /**
22
+ * Renders all pieces on the board.
23
+ *
24
+ * Each piece gets a stable key (from useBoardPieces) so React doesn't
25
+ * unmount/remount pieces that moved — it updates their position props
26
+ * and the BoardPieceView animates the transition.
27
+ */
28
+ export const BoardPiecesLayer = React.memo(function BoardPiecesLayer({
29
+ pieces,
30
+ squareSize,
31
+ orientation,
32
+ moveDuration,
33
+ animationConfig,
34
+ renderPiece,
35
+ activeSquare,
36
+ isDragging,
37
+ exitingAnimation,
38
+ }: BoardPiecesProps) {
39
+ return (
40
+ <>
41
+ {pieces.map((piece) => {
42
+ const { x, y } = squareToXY(piece.square, squareSize, orientation);
43
+
44
+ return (
45
+ <BoardPieceView
46
+ key={piece.id}
47
+ targetX={x}
48
+ targetY={y}
49
+ squareSize={squareSize}
50
+ moveDuration={moveDuration}
51
+ animationConfig={animationConfig}
52
+ activeSquare={activeSquare}
53
+ isDragging={isDragging}
54
+ square={piece.square}
55
+ exitingAnimation={exitingAnimation}
56
+ >
57
+ {renderPiece(piece.code, squareSize)}
58
+ </BoardPieceView>
59
+ );
60
+ })}
61
+ </>
62
+ );
63
+ });