react-native-chess-kit 0.1.0 → 0.2.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 (109) hide show
  1. package/lib/commonjs/board-annotations.js +131 -0
  2. package/lib/commonjs/board-annotations.js.map +1 -0
  3. package/lib/commonjs/board-arrows.js +164 -0
  4. package/lib/commonjs/board-arrows.js.map +1 -0
  5. package/lib/commonjs/board-highlights.js +212 -0
  6. package/lib/commonjs/board-highlights.js.map +1 -0
  7. package/lib/commonjs/board-piece.js +71 -25
  8. package/lib/commonjs/board-piece.js.map +1 -1
  9. package/lib/commonjs/board-pieces.js +2 -0
  10. package/lib/commonjs/board-pieces.js.map +1 -1
  11. package/lib/commonjs/board.js +392 -42
  12. package/lib/commonjs/board.js.map +1 -1
  13. package/lib/commonjs/constants.js +104 -0
  14. package/lib/commonjs/constants.js.map +1 -0
  15. package/lib/commonjs/index.js +128 -0
  16. package/lib/commonjs/index.js.map +1 -1
  17. package/lib/commonjs/pieces/default-pieces.js +536 -0
  18. package/lib/commonjs/pieces/default-pieces.js.map +1 -0
  19. package/lib/commonjs/pieces/index.js +13 -0
  20. package/lib/commonjs/pieces/index.js.map +1 -0
  21. package/lib/commonjs/promotion-picker.js +129 -0
  22. package/lib/commonjs/promotion-picker.js.map +1 -0
  23. package/lib/commonjs/static-board.js +150 -0
  24. package/lib/commonjs/static-board.js.map +1 -0
  25. package/lib/commonjs/themes.js +175 -0
  26. package/lib/commonjs/themes.js.map +1 -0
  27. package/lib/commonjs/use-board-gesture.js +184 -11
  28. package/lib/commonjs/use-board-gesture.js.map +1 -1
  29. package/lib/commonjs/use-premove.js +44 -0
  30. package/lib/commonjs/use-premove.js.map +1 -0
  31. package/lib/module/board-annotations.js +126 -0
  32. package/lib/module/board-annotations.js.map +1 -0
  33. package/lib/module/board-arrows.js +161 -0
  34. package/lib/module/board-arrows.js.map +1 -0
  35. package/lib/module/board-highlights.js +206 -0
  36. package/lib/module/board-highlights.js.map +1 -0
  37. package/lib/module/board-piece.js +72 -26
  38. package/lib/module/board-piece.js.map +1 -1
  39. package/lib/module/board-pieces.js +2 -0
  40. package/lib/module/board-pieces.js.map +1 -1
  41. package/lib/module/board.js +395 -44
  42. package/lib/module/board.js.map +1 -1
  43. package/lib/module/constants.js +100 -0
  44. package/lib/module/constants.js.map +1 -0
  45. package/lib/module/index.js +29 -1
  46. package/lib/module/index.js.map +1 -1
  47. package/lib/module/pieces/default-pieces.js +530 -0
  48. package/lib/module/pieces/default-pieces.js.map +1 -0
  49. package/lib/module/pieces/index.js +4 -0
  50. package/lib/module/pieces/index.js.map +1 -0
  51. package/lib/module/promotion-picker.js +124 -0
  52. package/lib/module/promotion-picker.js.map +1 -0
  53. package/lib/module/static-board.js +146 -0
  54. package/lib/module/static-board.js.map +1 -0
  55. package/lib/module/themes.js +171 -0
  56. package/lib/module/themes.js.map +1 -0
  57. package/lib/module/use-board-gesture.js +185 -11
  58. package/lib/module/use-board-gesture.js.map +1 -1
  59. package/lib/module/use-premove.js +40 -0
  60. package/lib/module/use-premove.js.map +1 -0
  61. package/lib/typescript/board-annotations.d.ts +30 -0
  62. package/lib/typescript/board-annotations.d.ts.map +1 -0
  63. package/lib/typescript/board-arrows.d.ts +27 -0
  64. package/lib/typescript/board-arrows.d.ts.map +1 -0
  65. package/lib/typescript/board-highlights.d.ts +65 -0
  66. package/lib/typescript/board-highlights.d.ts.map +1 -0
  67. package/lib/typescript/board-piece.d.ts +19 -9
  68. package/lib/typescript/board-piece.d.ts.map +1 -1
  69. package/lib/typescript/board-pieces.d.ts +2 -1
  70. package/lib/typescript/board-pieces.d.ts.map +1 -1
  71. package/lib/typescript/board.d.ts +11 -2
  72. package/lib/typescript/board.d.ts.map +1 -1
  73. package/lib/typescript/constants.d.ts +54 -0
  74. package/lib/typescript/constants.d.ts.map +1 -0
  75. package/lib/typescript/index.d.ts +9 -1
  76. package/lib/typescript/index.d.ts.map +1 -1
  77. package/lib/typescript/pieces/default-pieces.d.ts +3 -0
  78. package/lib/typescript/pieces/default-pieces.d.ts.map +1 -0
  79. package/lib/typescript/pieces/index.d.ts +2 -0
  80. package/lib/typescript/pieces/index.d.ts.map +1 -0
  81. package/lib/typescript/promotion-picker.d.ts +30 -0
  82. package/lib/typescript/promotion-picker.d.ts.map +1 -0
  83. package/lib/typescript/static-board.d.ts +12 -0
  84. package/lib/typescript/static-board.d.ts.map +1 -0
  85. package/lib/typescript/themes.d.ts +15 -0
  86. package/lib/typescript/themes.d.ts.map +1 -0
  87. package/lib/typescript/types.d.ts +194 -24
  88. package/lib/typescript/types.d.ts.map +1 -1
  89. package/lib/typescript/use-board-gesture.d.ts +28 -2
  90. package/lib/typescript/use-board-gesture.d.ts.map +1 -1
  91. package/lib/typescript/use-premove.d.ts +31 -0
  92. package/lib/typescript/use-premove.d.ts.map +1 -0
  93. package/package.json +4 -2
  94. package/src/board-annotations.tsx +147 -0
  95. package/src/board-arrows.tsx +197 -0
  96. package/src/board-highlights.tsx +226 -0
  97. package/src/board-piece.tsx +77 -29
  98. package/src/board-pieces.tsx +4 -1
  99. package/src/board.tsx +462 -46
  100. package/src/constants.ts +100 -0
  101. package/src/index.ts +62 -1
  102. package/src/pieces/default-pieces.tsx +383 -0
  103. package/src/pieces/index.ts +1 -0
  104. package/src/promotion-picker.tsx +147 -0
  105. package/src/static-board.tsx +150 -0
  106. package/src/themes.ts +129 -0
  107. package/src/types.ts +251 -25
  108. package/src/use-board-gesture.ts +219 -8
  109. package/src/use-premove.ts +59 -0
@@ -3,17 +3,24 @@ import Animated, {
3
3
  useAnimatedStyle,
4
4
  useSharedValue,
5
5
  withTiming,
6
+ withSpring,
7
+ FadeOut,
6
8
  type SharedValue,
7
9
  } from 'react-native-reanimated';
8
10
 
11
+ import type { AnimationConfig } from './types';
12
+ import { DEFAULT_MOVE_DURATION, CAPTURE_FADE_DURATION } from './constants';
13
+
9
14
  type BoardPieceProps = {
10
15
  /** Target pixel position (top-left of destination square) */
11
16
  targetX: number;
12
17
  targetY: number;
13
18
  /** Square size in pixels */
14
19
  squareSize: number;
15
- /** Move animation duration in ms */
16
- moveDuration: number;
20
+ /** Animation config for piece movement (timing or spring) */
21
+ animationConfig?: AnimationConfig;
22
+ /** Fallback move duration if animationConfig not provided */
23
+ moveDuration?: number;
17
24
  /** The piece visual (rendered by parent via renderPiece) */
18
25
  children: React.ReactElement;
19
26
  /** Gesture state: is this piece currently being dragged? */
@@ -23,26 +30,62 @@ type BoardPieceProps = {
23
30
  square: string;
24
31
  };
25
32
 
33
+ /**
34
+ * Animate a shared value using the provided AnimationConfig.
35
+ * Falls back to withTiming with moveDuration for backwards compatibility.
36
+ */
37
+ function animateValue(
38
+ target: number,
39
+ config?: AnimationConfig,
40
+ moveDuration?: number,
41
+ ): number {
42
+ if (config) {
43
+ if (config.type === 'spring') {
44
+ return withSpring(target, {
45
+ damping: config.damping ?? 15,
46
+ stiffness: config.stiffness ?? 200,
47
+ mass: config.mass ?? 1,
48
+ });
49
+ }
50
+ // timing
51
+ return withTiming(target, {
52
+ duration: config.duration ?? DEFAULT_MOVE_DURATION,
53
+ });
54
+ }
55
+
56
+ const duration = moveDuration ?? DEFAULT_MOVE_DURATION;
57
+ if (duration <= 0) return target;
58
+ return withTiming(target, { duration });
59
+ }
60
+
26
61
  /**
27
62
  * A single animated chess piece.
28
63
  *
29
- * Animates ONLY `transform` and `opacity` Reanimated's fast path on Android.
30
- * No layout properties (top/left/width/height) are animated, avoiding costly
31
- * layout recalculations on low-end devices.
64
+ * Uses two nested Animated.Views to avoid the Reanimated warning
65
+ * "Property opacity may be overwritten by a layout animation":
66
+ *
67
+ * Outer view: position (transform) + exiting layout animation (FadeOut)
68
+ * Inner view: drag-hide opacity
69
+ *
70
+ * Only `transform` and `opacity` are animated — Reanimated's fast path
71
+ * on Android. No layout properties (top/left/width/height), avoiding
72
+ * costly layout recalculations on low-end devices.
32
73
  *
33
74
  * During drag:
34
- * - Original piece hides (opacity: 0) — the drag ghost shows instead
35
- * - No position changes on the original piece during drag
75
+ * - Inner view hides (opacity: 0) — the drag ghost shows instead
36
76
  *
37
77
  * After a move:
38
- * - Snaps to new position via withTiming on translateX/translateY
39
- * - Duration controlled by user's animation speed setting
78
+ * - Outer view snaps to new position via withTiming/withSpring
79
+ *
80
+ * On capture (unmount):
81
+ * - Outer view fades out via exiting FadeOut (no conflict with inner opacity)
40
82
  */
41
83
  export const BoardPieceView = React.memo(
42
84
  function BoardPieceView({
43
85
  targetX,
44
86
  targetY,
45
87
  squareSize,
88
+ animationConfig,
46
89
  moveDuration,
47
90
  children,
48
91
  activeSquare,
@@ -57,25 +100,23 @@ export const BoardPieceView = React.memo(
57
100
  // useEffect is the correct pattern for reacting to JS prop changes —
58
101
  // useDerivedValue is meant for shared-value-to-shared-value derivation.
59
102
  useEffect(() => {
60
- currentX.value = moveDuration > 0
61
- ? withTiming(targetX, { duration: moveDuration })
62
- : targetX;
63
- currentY.value = moveDuration > 0
64
- ? withTiming(targetY, { duration: moveDuration })
65
- : targetY;
66
- }, [targetX, targetY, moveDuration, currentX, currentY]);
103
+ currentX.value = animateValue(targetX, animationConfig, moveDuration);
104
+ currentY.value = animateValue(targetY, animationConfig, moveDuration);
105
+ }, [targetX, targetY, animationConfig, moveDuration, currentX, currentY]);
67
106
 
68
- const animatedStyle = useAnimatedStyle(() => {
69
- const isBeingDragged = isDragging.value && activeSquare.value === square;
107
+ // Position style on outer view — no opacity here to avoid conflict
108
+ // with the FadeOut exiting layout animation
109
+ const positionStyle = useAnimatedStyle(() => ({
110
+ transform: [
111
+ { translateX: currentX.value },
112
+ { translateY: currentY.value },
113
+ ],
114
+ }));
70
115
 
71
- return {
72
- transform: [
73
- { translateX: currentX.value },
74
- { translateY: currentY.value },
75
- ],
76
- // Hide original piece during drag — drag ghost renders on top
77
- opacity: isBeingDragged ? 0 : 1,
78
- };
116
+ // Drag-hide opacity on inner view — separate from the exiting animation
117
+ const opacityStyle = useAnimatedStyle(() => {
118
+ const isBeingDragged = isDragging.value && activeSquare.value === square;
119
+ return { opacity: isBeingDragged ? 0 : 1 };
79
120
  });
80
121
 
81
122
  return (
@@ -86,19 +127,26 @@ export const BoardPieceView = React.memo(
86
127
  width: squareSize,
87
128
  height: squareSize,
88
129
  },
89
- animatedStyle,
130
+ positionStyle,
90
131
  ]}
132
+ // Fade out when this piece is captured (removed from the piece list).
133
+ // Lives on the outer view so it doesn't conflict with the
134
+ // drag-hide opacity on the inner view.
135
+ exiting={FadeOut.duration(CAPTURE_FADE_DURATION)}
91
136
  >
92
- {children}
137
+ <Animated.View style={[{ flex: 1 }, opacityStyle]}>
138
+ {children}
139
+ </Animated.View>
93
140
  </Animated.View>
94
141
  );
95
142
  },
96
- // Custom comparator: only re-render when position or square changes
143
+ // Custom comparator: only re-render when position, square, or animation config changes
97
144
  (prev, next) =>
98
145
  prev.targetX === next.targetX &&
99
146
  prev.targetY === next.targetY &&
100
147
  prev.square === next.square &&
101
148
  prev.squareSize === next.squareSize &&
102
149
  prev.moveDuration === next.moveDuration &&
150
+ prev.animationConfig === next.animationConfig &&
103
151
  prev.children === next.children,
104
152
  );
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { SharedValue } from 'react-native-reanimated';
3
3
 
4
- import type { ChessColor, BoardPiece } from './types';
4
+ import type { ChessColor, BoardPiece, AnimationConfig } from './types';
5
5
  import { BoardPieceView } from './board-piece';
6
6
  import { squareToXY } from './use-board-pieces';
7
7
 
@@ -10,6 +10,7 @@ type BoardPiecesProps = {
10
10
  squareSize: number;
11
11
  orientation: ChessColor;
12
12
  moveDuration: number;
13
+ animationConfig?: AnimationConfig;
13
14
  renderPiece: (code: string, size: number) => React.ReactElement;
14
15
  activeSquare: SharedValue<string | null>;
15
16
  isDragging: SharedValue<boolean>;
@@ -27,6 +28,7 @@ export const BoardPiecesLayer = React.memo(function BoardPiecesLayer({
27
28
  squareSize,
28
29
  orientation,
29
30
  moveDuration,
31
+ animationConfig,
30
32
  renderPiece,
31
33
  activeSquare,
32
34
  isDragging,
@@ -43,6 +45,7 @@ export const BoardPiecesLayer = React.memo(function BoardPiecesLayer({
43
45
  targetY={y}
44
46
  squareSize={squareSize}
45
47
  moveDuration={moveDuration}
48
+ animationConfig={animationConfig}
46
49
  activeSquare={activeSquare}
47
50
  isDragging={isDragging}
48
51
  square={piece.square}