react-native-chess-kit 0.5.3 → 0.5.4
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/LICENSE +21 -21
- package/README.md +187 -187
- package/lib/commonjs/board-annotations.js +8 -8
- package/lib/commonjs/board-annotations.js.map +1 -1
- package/lib/commonjs/board-arrows.js +7 -7
- package/lib/commonjs/board-arrows.js.map +1 -1
- package/lib/commonjs/board-background.js +5 -5
- package/lib/commonjs/board-background.js.map +1 -1
- package/lib/commonjs/board-coordinates.js.map +1 -1
- package/lib/commonjs/board-drag-ghost.js +10 -10
- package/lib/commonjs/board-drag-ghost.js.map +1 -1
- package/lib/commonjs/board-highlights.js +15 -15
- package/lib/commonjs/board-highlights.js.map +1 -1
- package/lib/commonjs/board-legal-dots.js +5 -5
- package/lib/commonjs/board-legal-dots.js.map +1 -1
- package/lib/commonjs/board-piece.js +25 -25
- package/lib/commonjs/board-piece.js.map +1 -1
- package/lib/commonjs/board-pieces.js +6 -6
- package/lib/commonjs/board-pieces.js.map +1 -1
- package/lib/commonjs/board.js +32 -28
- package/lib/commonjs/board.js.map +1 -1
- package/lib/commonjs/constants.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/pieces/default-pieces.js.map +1 -1
- package/lib/commonjs/pieces/index.js.map +1 -1
- package/lib/commonjs/promotion-picker.js.map +1 -1
- package/lib/commonjs/static-board.js.map +1 -1
- package/lib/commonjs/themes.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/use-board-gesture.js.map +1 -1
- package/lib/commonjs/use-board-pieces.js +15 -15
- package/lib/commonjs/use-board-pieces.js.map +1 -1
- package/lib/commonjs/use-board-state.js +8 -8
- package/lib/commonjs/use-board-state.js.map +1 -1
- package/lib/commonjs/use-premove.js +12 -12
- package/lib/commonjs/use-premove.js.map +1 -1
- package/lib/module/board-annotations.js +8 -8
- package/lib/module/board-annotations.js.map +1 -1
- package/lib/module/board-arrows.js +7 -7
- package/lib/module/board-arrows.js.map +1 -1
- package/lib/module/board-background.js +5 -5
- package/lib/module/board-background.js.map +1 -1
- package/lib/module/board-coordinates.js.map +1 -1
- package/lib/module/board-drag-ghost.js +10 -10
- package/lib/module/board-drag-ghost.js.map +1 -1
- package/lib/module/board-highlights.js +15 -15
- package/lib/module/board-highlights.js.map +1 -1
- package/lib/module/board-legal-dots.js +5 -5
- package/lib/module/board-legal-dots.js.map +1 -1
- package/lib/module/board-piece.js +25 -25
- package/lib/module/board-piece.js.map +1 -1
- package/lib/module/board-pieces.js +6 -6
- package/lib/module/board-pieces.js.map +1 -1
- package/lib/module/board.js +32 -28
- package/lib/module/board.js.map +1 -1
- package/lib/module/constants.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/pieces/default-pieces.js.map +1 -1
- package/lib/module/pieces/index.js.map +1 -1
- package/lib/module/promotion-picker.js.map +1 -1
- package/lib/module/static-board.js.map +1 -1
- package/lib/module/themes.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/use-board-gesture.js.map +1 -1
- package/lib/module/use-board-pieces.js +15 -15
- package/lib/module/use-board-pieces.js.map +1 -1
- package/lib/module/use-board-state.js +8 -8
- package/lib/module/use-board-state.js.map +1 -1
- package/lib/module/use-premove.js +12 -12
- package/lib/module/use-premove.js.map +1 -1
- package/lib/typescript/types.d.ts +2 -1
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +95 -95
- package/src/board-annotations.tsx +147 -147
- package/src/board-arrows.tsx +197 -197
- package/src/board-background.tsx +46 -46
- package/src/board-drag-ghost.tsx +132 -132
- package/src/board-highlights.tsx +226 -226
- package/src/board-legal-dots.tsx +73 -73
- package/src/board-piece.tsx +160 -160
- package/src/board-pieces.tsx +63 -63
- package/src/board.tsx +688 -688
- package/src/constants.ts +103 -103
- package/src/index.ts +101 -101
- package/src/pieces/default-pieces.tsx +383 -383
- package/src/pieces/index.ts +1 -1
- package/src/themes.ts +129 -129
- package/src/types.ts +394 -394
- package/src/use-board-pieces.ts +158 -158
- package/src/use-board-state.ts +120 -120
- package/src/use-premove.ts +59 -59
package/src/board-arrows.tsx
CHANGED
|
@@ -1,197 +1,197 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { View } from 'react-native';
|
|
3
|
-
import Svg, { Line, Polygon, Circle as SvgCircle } from 'react-native-svg';
|
|
4
|
-
|
|
5
|
-
import type { ChessColor, ArrowData, ShapeData } from './types';
|
|
6
|
-
import {
|
|
7
|
-
DEFAULT_ARROW_COLOR,
|
|
8
|
-
DEFAULT_SHAPE_COLOR,
|
|
9
|
-
ARROW_STROKE_WIDTH,
|
|
10
|
-
ARROW_HEAD_SIZE,
|
|
11
|
-
ARROW_SHORTEN_BY,
|
|
12
|
-
} from './constants';
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Coordinate utilities (percentage-based viewBox 0-100)
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
function squareToViewBoxCenter(
|
|
19
|
-
square: string,
|
|
20
|
-
orientation: ChessColor,
|
|
21
|
-
): { x: number; y: number } {
|
|
22
|
-
const fileIdx = square.charCodeAt(0) - 97;
|
|
23
|
-
const rankIdx = parseInt(square[1], 10) - 1;
|
|
24
|
-
const col = orientation === 'white' ? fileIdx : 7 - fileIdx;
|
|
25
|
-
const row = orientation === 'white' ? 7 - rankIdx : rankIdx;
|
|
26
|
-
return {
|
|
27
|
-
x: (col + 0.5) * 12.5,
|
|
28
|
-
y: (row + 0.5) * 12.5,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function calculateArrowPath(
|
|
33
|
-
from: { x: number; y: number },
|
|
34
|
-
to: { x: number; y: number },
|
|
35
|
-
shortenBy: number,
|
|
36
|
-
): { x1: number; y1: number; x2: number; y2: number } {
|
|
37
|
-
const dx = to.x - from.x;
|
|
38
|
-
const dy = to.y - from.y;
|
|
39
|
-
const len = Math.sqrt(dx * dx + dy * dy);
|
|
40
|
-
if (len === 0) return { x1: from.x, y1: from.y, x2: to.x, y2: to.y };
|
|
41
|
-
|
|
42
|
-
const ux = dx / len;
|
|
43
|
-
const uy = dy / len;
|
|
44
|
-
return {
|
|
45
|
-
x1: from.x + ux * shortenBy,
|
|
46
|
-
y1: from.y + uy * shortenBy,
|
|
47
|
-
x2: to.x - ux * shortenBy,
|
|
48
|
-
y2: to.y - uy * shortenBy,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
// Props
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
|
|
56
|
-
type BoardArrowsProps = {
|
|
57
|
-
boardSize: number;
|
|
58
|
-
orientation: ChessColor;
|
|
59
|
-
arrows?: ArrowData[];
|
|
60
|
-
shapes?: ShapeData[];
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
// Combined arrows + shapes SVG layer
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* SVG overlay for arrows and shapes drawn on the board.
|
|
69
|
-
*
|
|
70
|
-
* Uses a percentage-based 100x100 viewBox so coordinates map cleanly
|
|
71
|
-
* to the 8x8 grid (each square = 12.5 x 12.5 units).
|
|
72
|
-
*
|
|
73
|
-
* Renders above the pieces layer so arrows are always visible.
|
|
74
|
-
*/
|
|
75
|
-
export const BoardArrows = React.memo(function BoardArrows({
|
|
76
|
-
boardSize,
|
|
77
|
-
orientation,
|
|
78
|
-
arrows,
|
|
79
|
-
shapes,
|
|
80
|
-
}: BoardArrowsProps) {
|
|
81
|
-
const hasArrows = arrows && arrows.length > 0;
|
|
82
|
-
const hasShapes = shapes && shapes.length > 0;
|
|
83
|
-
|
|
84
|
-
if (!hasArrows && !hasShapes) return null;
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<View
|
|
88
|
-
style={{ position: 'absolute', width: boardSize, height: boardSize }}
|
|
89
|
-
pointerEvents="none"
|
|
90
|
-
>
|
|
91
|
-
<Svg viewBox="0 0 100 100" width={boardSize} height={boardSize}>
|
|
92
|
-
{/* Shapes (circles) -- drawn under arrows */}
|
|
93
|
-
{hasShapes &&
|
|
94
|
-
shapes.map((shape, i) => {
|
|
95
|
-
if (shape.type === 'circle') {
|
|
96
|
-
const center = squareToViewBoxCenter(shape.square, orientation);
|
|
97
|
-
const color = shape.color ?? DEFAULT_SHAPE_COLOR;
|
|
98
|
-
return (
|
|
99
|
-
<SvgCircle
|
|
100
|
-
key={`circle-${shape.square}-${i}`}
|
|
101
|
-
cx={center.x}
|
|
102
|
-
cy={center.y}
|
|
103
|
-
r={5.5}
|
|
104
|
-
fill="none"
|
|
105
|
-
stroke={color}
|
|
106
|
-
strokeWidth={1.2}
|
|
107
|
-
opacity={0.85}
|
|
108
|
-
/>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
})}
|
|
113
|
-
|
|
114
|
-
{/* Arrows */}
|
|
115
|
-
{hasArrows &&
|
|
116
|
-
arrows.map((arrow, i) => (
|
|
117
|
-
<ArrowSvg
|
|
118
|
-
key={`arrow-${arrow.from}-${arrow.to}-${i}`}
|
|
119
|
-
from={arrow.from}
|
|
120
|
-
to={arrow.to}
|
|
121
|
-
color={arrow.color ?? DEFAULT_ARROW_COLOR}
|
|
122
|
-
width={arrow.width ?? ARROW_STROKE_WIDTH}
|
|
123
|
-
orientation={orientation}
|
|
124
|
-
/>
|
|
125
|
-
))}
|
|
126
|
-
</Svg>
|
|
127
|
-
</View>
|
|
128
|
-
);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
// Single arrow SVG element
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
|
|
135
|
-
type ArrowSvgProps = {
|
|
136
|
-
from: string;
|
|
137
|
-
to: string;
|
|
138
|
-
color: string;
|
|
139
|
-
width: number;
|
|
140
|
-
orientation: ChessColor;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const ArrowSvg = React.memo(function ArrowSvg({
|
|
144
|
-
from,
|
|
145
|
-
to,
|
|
146
|
-
color,
|
|
147
|
-
width,
|
|
148
|
-
orientation,
|
|
149
|
-
}: ArrowSvgProps) {
|
|
150
|
-
const fromCoord = squareToViewBoxCenter(from, orientation);
|
|
151
|
-
const toCoord = squareToViewBoxCenter(to, orientation);
|
|
152
|
-
const path = calculateArrowPath(fromCoord, toCoord, ARROW_SHORTEN_BY);
|
|
153
|
-
|
|
154
|
-
const dx = path.x2 - path.x1;
|
|
155
|
-
const dy = path.y2 - path.y1;
|
|
156
|
-
const len = Math.sqrt(dx * dx + dy * dy);
|
|
157
|
-
|
|
158
|
-
if (len === 0) return null;
|
|
159
|
-
|
|
160
|
-
const ux = dx / len;
|
|
161
|
-
const uy = dy / len;
|
|
162
|
-
const headSize = ARROW_HEAD_SIZE;
|
|
163
|
-
|
|
164
|
-
const tip = { x: path.x2, y: path.y2 };
|
|
165
|
-
const baseLeft = {
|
|
166
|
-
x: path.x2 - ux * headSize * 2 + uy * headSize,
|
|
167
|
-
y: path.y2 - uy * headSize * 2 - ux * headSize,
|
|
168
|
-
};
|
|
169
|
-
const baseRight = {
|
|
170
|
-
x: path.x2 - ux * headSize * 2 - uy * headSize,
|
|
171
|
-
y: path.y2 - uy * headSize * 2 + ux * headSize,
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const arrowPoints = `${tip.x},${tip.y} ${baseLeft.x},${baseLeft.y} ${baseRight.x},${baseRight.y}`;
|
|
175
|
-
|
|
176
|
-
return (
|
|
177
|
-
<>
|
|
178
|
-
<Line
|
|
179
|
-
x1={path.x1}
|
|
180
|
-
y1={path.y1}
|
|
181
|
-
x2={path.x2 - ux * headSize * 2}
|
|
182
|
-
y2={path.y2 - uy * headSize * 2}
|
|
183
|
-
stroke={color}
|
|
184
|
-
strokeWidth={width}
|
|
185
|
-
strokeLinecap="round"
|
|
186
|
-
opacity={0.85}
|
|
187
|
-
/>
|
|
188
|
-
<Polygon points={arrowPoints} fill={color} opacity={0.85} />
|
|
189
|
-
</>
|
|
190
|
-
);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// ---------------------------------------------------------------------------
|
|
194
|
-
// Standalone exports for advanced consumers
|
|
195
|
-
// ---------------------------------------------------------------------------
|
|
196
|
-
|
|
197
|
-
export { ArrowSvg as Arrow };
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import Svg, { Line, Polygon, Circle as SvgCircle } from 'react-native-svg';
|
|
4
|
+
|
|
5
|
+
import type { ChessColor, ArrowData, ShapeData } from './types';
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_ARROW_COLOR,
|
|
8
|
+
DEFAULT_SHAPE_COLOR,
|
|
9
|
+
ARROW_STROKE_WIDTH,
|
|
10
|
+
ARROW_HEAD_SIZE,
|
|
11
|
+
ARROW_SHORTEN_BY,
|
|
12
|
+
} from './constants';
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Coordinate utilities (percentage-based viewBox 0-100)
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
function squareToViewBoxCenter(
|
|
19
|
+
square: string,
|
|
20
|
+
orientation: ChessColor,
|
|
21
|
+
): { x: number; y: number } {
|
|
22
|
+
const fileIdx = square.charCodeAt(0) - 97;
|
|
23
|
+
const rankIdx = parseInt(square[1], 10) - 1;
|
|
24
|
+
const col = orientation === 'white' ? fileIdx : 7 - fileIdx;
|
|
25
|
+
const row = orientation === 'white' ? 7 - rankIdx : rankIdx;
|
|
26
|
+
return {
|
|
27
|
+
x: (col + 0.5) * 12.5,
|
|
28
|
+
y: (row + 0.5) * 12.5,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function calculateArrowPath(
|
|
33
|
+
from: { x: number; y: number },
|
|
34
|
+
to: { x: number; y: number },
|
|
35
|
+
shortenBy: number,
|
|
36
|
+
): { x1: number; y1: number; x2: number; y2: number } {
|
|
37
|
+
const dx = to.x - from.x;
|
|
38
|
+
const dy = to.y - from.y;
|
|
39
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
40
|
+
if (len === 0) return { x1: from.x, y1: from.y, x2: to.x, y2: to.y };
|
|
41
|
+
|
|
42
|
+
const ux = dx / len;
|
|
43
|
+
const uy = dy / len;
|
|
44
|
+
return {
|
|
45
|
+
x1: from.x + ux * shortenBy,
|
|
46
|
+
y1: from.y + uy * shortenBy,
|
|
47
|
+
x2: to.x - ux * shortenBy,
|
|
48
|
+
y2: to.y - uy * shortenBy,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Props
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
type BoardArrowsProps = {
|
|
57
|
+
boardSize: number;
|
|
58
|
+
orientation: ChessColor;
|
|
59
|
+
arrows?: ArrowData[];
|
|
60
|
+
shapes?: ShapeData[];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Combined arrows + shapes SVG layer
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* SVG overlay for arrows and shapes drawn on the board.
|
|
69
|
+
*
|
|
70
|
+
* Uses a percentage-based 100x100 viewBox so coordinates map cleanly
|
|
71
|
+
* to the 8x8 grid (each square = 12.5 x 12.5 units).
|
|
72
|
+
*
|
|
73
|
+
* Renders above the pieces layer so arrows are always visible.
|
|
74
|
+
*/
|
|
75
|
+
export const BoardArrows = React.memo(function BoardArrows({
|
|
76
|
+
boardSize,
|
|
77
|
+
orientation,
|
|
78
|
+
arrows,
|
|
79
|
+
shapes,
|
|
80
|
+
}: BoardArrowsProps) {
|
|
81
|
+
const hasArrows = arrows && arrows.length > 0;
|
|
82
|
+
const hasShapes = shapes && shapes.length > 0;
|
|
83
|
+
|
|
84
|
+
if (!hasArrows && !hasShapes) return null;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<View
|
|
88
|
+
style={{ position: 'absolute', width: boardSize, height: boardSize }}
|
|
89
|
+
pointerEvents="none"
|
|
90
|
+
>
|
|
91
|
+
<Svg viewBox="0 0 100 100" width={boardSize} height={boardSize}>
|
|
92
|
+
{/* Shapes (circles) -- drawn under arrows */}
|
|
93
|
+
{hasShapes &&
|
|
94
|
+
shapes.map((shape, i) => {
|
|
95
|
+
if (shape.type === 'circle') {
|
|
96
|
+
const center = squareToViewBoxCenter(shape.square, orientation);
|
|
97
|
+
const color = shape.color ?? DEFAULT_SHAPE_COLOR;
|
|
98
|
+
return (
|
|
99
|
+
<SvgCircle
|
|
100
|
+
key={`circle-${shape.square}-${i}`}
|
|
101
|
+
cx={center.x}
|
|
102
|
+
cy={center.y}
|
|
103
|
+
r={5.5}
|
|
104
|
+
fill="none"
|
|
105
|
+
stroke={color}
|
|
106
|
+
strokeWidth={1.2}
|
|
107
|
+
opacity={0.85}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
})}
|
|
113
|
+
|
|
114
|
+
{/* Arrows */}
|
|
115
|
+
{hasArrows &&
|
|
116
|
+
arrows.map((arrow, i) => (
|
|
117
|
+
<ArrowSvg
|
|
118
|
+
key={`arrow-${arrow.from}-${arrow.to}-${i}`}
|
|
119
|
+
from={arrow.from}
|
|
120
|
+
to={arrow.to}
|
|
121
|
+
color={arrow.color ?? DEFAULT_ARROW_COLOR}
|
|
122
|
+
width={arrow.width ?? ARROW_STROKE_WIDTH}
|
|
123
|
+
orientation={orientation}
|
|
124
|
+
/>
|
|
125
|
+
))}
|
|
126
|
+
</Svg>
|
|
127
|
+
</View>
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Single arrow SVG element
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
type ArrowSvgProps = {
|
|
136
|
+
from: string;
|
|
137
|
+
to: string;
|
|
138
|
+
color: string;
|
|
139
|
+
width: number;
|
|
140
|
+
orientation: ChessColor;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const ArrowSvg = React.memo(function ArrowSvg({
|
|
144
|
+
from,
|
|
145
|
+
to,
|
|
146
|
+
color,
|
|
147
|
+
width,
|
|
148
|
+
orientation,
|
|
149
|
+
}: ArrowSvgProps) {
|
|
150
|
+
const fromCoord = squareToViewBoxCenter(from, orientation);
|
|
151
|
+
const toCoord = squareToViewBoxCenter(to, orientation);
|
|
152
|
+
const path = calculateArrowPath(fromCoord, toCoord, ARROW_SHORTEN_BY);
|
|
153
|
+
|
|
154
|
+
const dx = path.x2 - path.x1;
|
|
155
|
+
const dy = path.y2 - path.y1;
|
|
156
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
157
|
+
|
|
158
|
+
if (len === 0) return null;
|
|
159
|
+
|
|
160
|
+
const ux = dx / len;
|
|
161
|
+
const uy = dy / len;
|
|
162
|
+
const headSize = ARROW_HEAD_SIZE;
|
|
163
|
+
|
|
164
|
+
const tip = { x: path.x2, y: path.y2 };
|
|
165
|
+
const baseLeft = {
|
|
166
|
+
x: path.x2 - ux * headSize * 2 + uy * headSize,
|
|
167
|
+
y: path.y2 - uy * headSize * 2 - ux * headSize,
|
|
168
|
+
};
|
|
169
|
+
const baseRight = {
|
|
170
|
+
x: path.x2 - ux * headSize * 2 - uy * headSize,
|
|
171
|
+
y: path.y2 - uy * headSize * 2 + ux * headSize,
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const arrowPoints = `${tip.x},${tip.y} ${baseLeft.x},${baseLeft.y} ${baseRight.x},${baseRight.y}`;
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<>
|
|
178
|
+
<Line
|
|
179
|
+
x1={path.x1}
|
|
180
|
+
y1={path.y1}
|
|
181
|
+
x2={path.x2 - ux * headSize * 2}
|
|
182
|
+
y2={path.y2 - uy * headSize * 2}
|
|
183
|
+
stroke={color}
|
|
184
|
+
strokeWidth={width}
|
|
185
|
+
strokeLinecap="round"
|
|
186
|
+
opacity={0.85}
|
|
187
|
+
/>
|
|
188
|
+
<Polygon points={arrowPoints} fill={color} opacity={0.85} />
|
|
189
|
+
</>
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// Standalone exports for advanced consumers
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
|
|
197
|
+
export { ArrowSvg as Arrow };
|
package/src/board-background.tsx
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { View } from 'react-native';
|
|
3
|
-
|
|
4
|
-
type BoardBackgroundProps = {
|
|
5
|
-
boardSize: number;
|
|
6
|
-
lightColor: string;
|
|
7
|
-
darkColor: string;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 64 static colored squares forming the chess board grid.
|
|
12
|
-
*
|
|
13
|
-
* These are plain Views with backgroundColor — no animations, no gesture
|
|
14
|
-
* handlers. They never re-render after mount unless the board theme changes.
|
|
15
|
-
*/
|
|
16
|
-
export const BoardBackground = React.memo(function BoardBackground({
|
|
17
|
-
boardSize,
|
|
18
|
-
lightColor,
|
|
19
|
-
darkColor,
|
|
20
|
-
}: BoardBackgroundProps) {
|
|
21
|
-
const squareSize = boardSize / 8;
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<View style={{ width: boardSize, height: boardSize, flexDirection: 'row', flexWrap: 'wrap' }}>
|
|
25
|
-
{SQUARE_INDICES.map((i) => {
|
|
26
|
-
const row = Math.floor(i / 8);
|
|
27
|
-
const col = i % 8;
|
|
28
|
-
const isLight = (row + col) % 2 === 0;
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<View
|
|
32
|
-
key={i}
|
|
33
|
-
style={{
|
|
34
|
-
width: squareSize,
|
|
35
|
-
height: squareSize,
|
|
36
|
-
backgroundColor: isLight ? lightColor : darkColor,
|
|
37
|
-
}}
|
|
38
|
-
/>
|
|
39
|
-
);
|
|
40
|
-
})}
|
|
41
|
-
</View>
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Pre-computed array of 0-63 to avoid allocation on every render
|
|
46
|
-
const SQUARE_INDICES = Array.from({ length: 64 }, (_, i) => i);
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type BoardBackgroundProps = {
|
|
5
|
+
boardSize: number;
|
|
6
|
+
lightColor: string;
|
|
7
|
+
darkColor: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 64 static colored squares forming the chess board grid.
|
|
12
|
+
*
|
|
13
|
+
* These are plain Views with backgroundColor — no animations, no gesture
|
|
14
|
+
* handlers. They never re-render after mount unless the board theme changes.
|
|
15
|
+
*/
|
|
16
|
+
export const BoardBackground = React.memo(function BoardBackground({
|
|
17
|
+
boardSize,
|
|
18
|
+
lightColor,
|
|
19
|
+
darkColor,
|
|
20
|
+
}: BoardBackgroundProps) {
|
|
21
|
+
const squareSize = boardSize / 8;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<View style={{ width: boardSize, height: boardSize, flexDirection: 'row', flexWrap: 'wrap' }}>
|
|
25
|
+
{SQUARE_INDICES.map((i) => {
|
|
26
|
+
const row = Math.floor(i / 8);
|
|
27
|
+
const col = i % 8;
|
|
28
|
+
const isLight = (row + col) % 2 === 0;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View
|
|
32
|
+
key={i}
|
|
33
|
+
style={{
|
|
34
|
+
width: squareSize,
|
|
35
|
+
height: squareSize,
|
|
36
|
+
backgroundColor: isLight ? lightColor : darkColor,
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
})}
|
|
41
|
+
</View>
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Pre-computed array of 0-63 to avoid allocation on every render
|
|
46
|
+
const SQUARE_INDICES = Array.from({ length: 64 }, (_, i) => i);
|