@ankhorage/zora 25.11.1 → 26.0.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.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -4
- package/dist/capabilities/index.js +65 -41
- package/dist/capabilities/index.js.map +3 -3
- package/dist/features/chess/adapters/inbound/ChessBoard.d.ts +1 -1
- package/dist/features/chess/adapters/inbound/ChessBoard.d.ts.map +1 -1
- package/dist/features/chess/adapters/inbound/ChessBoard.js +130 -83
- package/dist/features/chess/adapters/inbound/ChessBoard.js.map +1 -1
- package/dist/features/chess/meta.d.ts +97 -72
- package/dist/features/chess/meta.d.ts.map +1 -1
- package/dist/features/chess/meta.js +64 -40
- package/dist/features/chess/meta.js.map +1 -1
- package/dist/features/chess/public.d.ts +1 -7
- package/dist/features/chess/public.d.ts.map +1 -1
- package/dist/features/chess/public.js +0 -6
- package/dist/features/chess/public.js.map +1 -1
- package/dist/features/chess/utils/createChessBoardCellPressHandler.d.ts +6 -0
- package/dist/features/chess/utils/createChessBoardCellPressHandler.d.ts.map +1 -0
- package/dist/features/chess/utils/createChessBoardCellPressHandler.js +17 -0
- package/dist/features/chess/utils/createChessBoardCellPressHandler.js.map +1 -0
- package/dist/features/chess/utils/createChessBoardCells.d.ts +12 -0
- package/dist/features/chess/utils/createChessBoardCells.d.ts.map +1 -0
- package/dist/features/chess/utils/createChessBoardCells.js +28 -0
- package/dist/features/chess/utils/createChessBoardCells.js.map +1 -0
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js +2 -3
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js +3 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.d.ts +5 -5
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.d.ts.map +1 -1
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.js +13 -7
- package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.js.map +1 -1
- package/dist/readerFree.d.ts +2 -2
- package/dist/readerFree.d.ts.map +1 -1
- package/dist/readerFree.js +1 -1
- package/dist/readerFree.js.map +1 -1
- package/dist/types/authoring.d.ts +2 -1
- package/dist/types/authoring.d.ts.map +1 -1
- package/dist/types/authoring.js.map +1 -1
- package/dist/types/chess.d.ts +27 -20
- package/dist/types/chess.d.ts.map +1 -1
- package/dist/types/chess.js.map +1 -1
- package/package.json +34 -94
- package/src/features/chess/adapters/inbound/ChessBoard.tsx +263 -112
- package/src/features/chess/meta.ts +64 -40
- package/src/features/chess/public.test.tsx +77 -228
- package/src/features/chess/public.ts +2 -9
- package/src/features/chess/utils/createChessBoardCellPressHandler.ts +30 -0
- package/src/features/chess/utils/createChessBoardCells.ts +54 -0
- package/src/features/chessTabletopOwnership.test.ts +3 -7
- package/src/features/graph-view/adapters/inbound/web-artifact/createGraphController.test.ts +1 -2
- package/src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts +2 -3
- package/src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.test.ts +45 -0
- package/src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.ts +3 -1
- package/src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.test.ts +65 -3
- package/src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.ts +13 -7
- package/src/features/registry/componentMeta.test.ts +12 -1
- package/src/readerFree.ts +3 -15
- package/src/types/authoring.ts +2 -1
- package/src/types/chess.ts +28 -21
- package/web-dist/chunks/Accordion-91sjb3zh.js +453 -0
- package/web-dist/components/chess-board/ChessBoard.js +2 -1
- package/web-dist/components/graph-view/GraphView.js +878 -317
- package/web-dist/components/opening-book/OpeningBook.js +2 -1
- package/web-dist/manifest.json +8 -4
- package/dist/features/chess/utils/chessEngine.d.ts +0 -8
- package/dist/features/chess/utils/chessEngine.d.ts.map +0 -1
- package/dist/features/chess/utils/chessEngine.js +0 -71
- package/dist/features/chess/utils/chessEngine.js.map +0 -1
- package/dist/features/chess/utils/chessSquares.d.ts +0 -4
- package/dist/features/chess/utils/chessSquares.d.ts.map +0 -1
- package/dist/features/chess/utils/chessSquares.js +0 -3
- package/dist/features/chess/utils/chessSquares.js.map +0 -1
- package/dist/features/chess/utils/createBoardSquares.d.ts +0 -4
- package/dist/features/chess/utils/createBoardSquares.d.ts.map +0 -1
- package/dist/features/chess/utils/createBoardSquares.js +0 -9
- package/dist/features/chess/utils/createBoardSquares.js.map +0 -1
- package/dist/features/chess/utils/getSquareFile.d.ts +0 -4
- package/dist/features/chess/utils/getSquareFile.d.ts.map +0 -1
- package/dist/features/chess/utils/getSquareFile.js +0 -5
- package/dist/features/chess/utils/getSquareFile.js.map +0 -1
- package/dist/features/chess/utils/getSquareRank.d.ts +0 -4
- package/dist/features/chess/utils/getSquareRank.d.ts.map +0 -1
- package/dist/features/chess/utils/getSquareRank.js +0 -5
- package/dist/features/chess/utils/getSquareRank.js.map +0 -1
- package/dist/features/chess/utils/isLightSquare.d.ts +0 -4
- package/dist/features/chess/utils/isLightSquare.d.ts.map +0 -1
- package/dist/features/chess/utils/isLightSquare.js +0 -6
- package/dist/features/chess/utils/isLightSquare.js.map +0 -1
- package/src/features/chess/utils/chessEngine.test.ts +0 -35
- package/src/features/chess/utils/chessEngine.ts +0 -83
- package/src/features/chess/utils/chessSquares.ts +0 -6
- package/src/features/chess/utils/createBoardSquares.ts +0 -13
- package/src/features/chess/utils/getSquareFile.ts +0 -6
- package/src/features/chess/utils/getSquareRank.ts +0 -6
- package/src/features/chess/utils/isLightSquare.ts +0 -8
- package/web-dist/chunks/Accordion-xcm1qc39.js +0 -3813
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/zora",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "26.0.1",
|
|
5
5
|
"description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/zora#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"@ankhorage/runtime": "^5.2.4",
|
|
52
52
|
"@ankhorage/surface": "^9.4.15",
|
|
53
53
|
"@ankhorage/utility": "^1.10.0",
|
|
54
|
-
"chess.js": "^1.4.0",
|
|
55
54
|
"expo-document-picker": "~57.0.3",
|
|
56
55
|
"expo-image-picker": "~57.0.20"
|
|
57
56
|
},
|
|
@@ -155,6 +154,7 @@
|
|
|
155
154
|
"format:check": "ankhorage-prettier --check .",
|
|
156
155
|
"prepack": "bun run build",
|
|
157
156
|
"test": "bun run build && bun test src examples/grid-workspaces/time examples/grid-workspaces/plugins --isolate",
|
|
157
|
+
"test:graph-view:chromium": "bun scripts/test-graph-view-chromium.ts",
|
|
158
158
|
"typecheck": "bun x tsc --noEmit -p tsconfig.json && bun x tsc --noEmit -p tsconfig.scripts.json && bun x tsc -p tsconfig.typecheck.json",
|
|
159
159
|
"version-packages": "ankhorage-changeset version"
|
|
160
160
|
},
|
|
@@ -171,8 +171,8 @@
|
|
|
171
171
|
"@types/react": "^19.3.0",
|
|
172
172
|
"@types/react-dom": "^19.3.0",
|
|
173
173
|
"@types/react-native-web": "^0.19.3",
|
|
174
|
-
"cytoscape": "^3.
|
|
175
|
-
"cytoscape-elk": "^2.
|
|
174
|
+
"cytoscape": "^3.35.0",
|
|
175
|
+
"cytoscape-elk": "^2.4.0",
|
|
176
176
|
"happy-dom": "^21.0.4",
|
|
177
177
|
"react": "19.2.3",
|
|
178
178
|
"react-dom": "19.2.3",
|
|
@@ -529,7 +529,7 @@
|
|
|
529
529
|
}
|
|
530
530
|
},
|
|
531
531
|
{
|
|
532
|
-
"id": "chess.
|
|
532
|
+
"id": "chess.cellPress",
|
|
533
533
|
"owner": "@ankhorage/zora",
|
|
534
534
|
"access": [
|
|
535
535
|
"emit"
|
|
@@ -540,67 +540,18 @@
|
|
|
540
540
|
"source"
|
|
541
541
|
]
|
|
542
542
|
},
|
|
543
|
-
"label": "
|
|
543
|
+
"label": "Cell press",
|
|
544
544
|
"output": {
|
|
545
545
|
"schema": {
|
|
546
546
|
"type": "object",
|
|
547
547
|
"properties": {
|
|
548
|
-
"
|
|
549
|
-
"type": "
|
|
550
|
-
"title": "
|
|
551
|
-
},
|
|
552
|
-
"to": {
|
|
553
|
-
"type": "string",
|
|
554
|
-
"title": "To"
|
|
555
|
-
},
|
|
556
|
-
"promotion": {
|
|
557
|
-
"type": "string",
|
|
558
|
-
"title": "Promotion"
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
},
|
|
564
|
-
{
|
|
565
|
-
"id": "chess.legalMove",
|
|
566
|
-
"owner": "@ankhorage/zora",
|
|
567
|
-
"access": [
|
|
568
|
-
"emit"
|
|
569
|
-
],
|
|
570
|
-
"binding": {
|
|
571
|
-
"kind": "event",
|
|
572
|
-
"bindableAs": [
|
|
573
|
-
"source"
|
|
574
|
-
]
|
|
575
|
-
},
|
|
576
|
-
"label": "Legal move",
|
|
577
|
-
"output": {
|
|
578
|
-
"schema": {
|
|
579
|
-
"type": "object",
|
|
580
|
-
"properties": {
|
|
581
|
-
"from": {
|
|
582
|
-
"type": "string",
|
|
583
|
-
"title": "From"
|
|
584
|
-
},
|
|
585
|
-
"to": {
|
|
586
|
-
"type": "string",
|
|
587
|
-
"title": "To"
|
|
588
|
-
},
|
|
589
|
-
"fen": {
|
|
590
|
-
"type": "string",
|
|
591
|
-
"title": "Position"
|
|
592
|
-
},
|
|
593
|
-
"san": {
|
|
594
|
-
"type": "string",
|
|
595
|
-
"title": "SAN"
|
|
596
|
-
},
|
|
597
|
-
"lan": {
|
|
598
|
-
"type": "string",
|
|
599
|
-
"title": "LAN"
|
|
548
|
+
"column": {
|
|
549
|
+
"type": "number",
|
|
550
|
+
"title": "Column"
|
|
600
551
|
},
|
|
601
|
-
"
|
|
602
|
-
"type": "
|
|
603
|
-
"title": "
|
|
552
|
+
"row": {
|
|
553
|
+
"type": "number",
|
|
554
|
+
"title": "Row"
|
|
604
555
|
}
|
|
605
556
|
}
|
|
606
557
|
}
|
|
@@ -624,16 +575,30 @@
|
|
|
624
575
|
"type": "object",
|
|
625
576
|
"properties": {
|
|
626
577
|
"from": {
|
|
627
|
-
"type": "
|
|
628
|
-
"
|
|
578
|
+
"type": "object",
|
|
579
|
+
"properties": {
|
|
580
|
+
"column": {
|
|
581
|
+
"type": "number",
|
|
582
|
+
"title": "From column"
|
|
583
|
+
},
|
|
584
|
+
"row": {
|
|
585
|
+
"type": "number",
|
|
586
|
+
"title": "From row"
|
|
587
|
+
}
|
|
588
|
+
}
|
|
629
589
|
},
|
|
630
590
|
"to": {
|
|
631
|
-
"type": "
|
|
632
|
-
"
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
591
|
+
"type": "object",
|
|
592
|
+
"properties": {
|
|
593
|
+
"column": {
|
|
594
|
+
"type": "number",
|
|
595
|
+
"title": "To column"
|
|
596
|
+
},
|
|
597
|
+
"row": {
|
|
598
|
+
"type": "number",
|
|
599
|
+
"title": "To row"
|
|
600
|
+
}
|
|
601
|
+
}
|
|
637
602
|
}
|
|
638
603
|
}
|
|
639
604
|
}
|
|
@@ -672,31 +637,6 @@
|
|
|
672
637
|
}
|
|
673
638
|
}
|
|
674
639
|
},
|
|
675
|
-
{
|
|
676
|
-
"id": "chess.squarePress",
|
|
677
|
-
"owner": "@ankhorage/zora",
|
|
678
|
-
"access": [
|
|
679
|
-
"emit"
|
|
680
|
-
],
|
|
681
|
-
"binding": {
|
|
682
|
-
"kind": "event",
|
|
683
|
-
"bindableAs": [
|
|
684
|
-
"source"
|
|
685
|
-
]
|
|
686
|
-
},
|
|
687
|
-
"label": "Square press",
|
|
688
|
-
"output": {
|
|
689
|
-
"schema": {
|
|
690
|
-
"type": "object",
|
|
691
|
-
"properties": {
|
|
692
|
-
"square": {
|
|
693
|
-
"type": "string",
|
|
694
|
-
"title": "Square"
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
},
|
|
700
640
|
{
|
|
701
641
|
"id": "chip.press",
|
|
702
642
|
"owner": "@ankhorage/zora",
|
|
@@ -2,17 +2,18 @@ import React from 'react';
|
|
|
2
2
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import type {
|
|
5
|
+
ChessBoardCell,
|
|
6
|
+
ChessBoardDimensions,
|
|
5
7
|
ChessBoardProps,
|
|
6
8
|
ChessMoveAttempt,
|
|
7
9
|
ChessPieceState,
|
|
8
|
-
ChessSquareId,
|
|
9
10
|
} from '../../../../types/chess';
|
|
11
|
+
import { GridView } from '../../../grid-view/public';
|
|
10
12
|
import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
|
|
11
13
|
import { useZoraTheme } from '../../../theme/composition/useZoraTheme';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
+
import { createChessBoardCellPressHandler } from '../../utils/createChessBoardCellPressHandler';
|
|
15
|
+
import { createChessBoardCells } from '../../utils/createChessBoardCells';
|
|
14
16
|
import { createChessBoardColorScheme } from '../../utils/createChessBoardColorScheme';
|
|
15
|
-
import { isLightSquare } from '../../utils/isLightSquare';
|
|
16
17
|
|
|
17
18
|
const symbols = new Map<string, string>([
|
|
18
19
|
['white:p', '♙'],
|
|
@@ -28,138 +29,293 @@ const symbols = new Map<string, string>([
|
|
|
28
29
|
['black:q', '♛'],
|
|
29
30
|
['black:k', '♚'],
|
|
30
31
|
]);
|
|
32
|
+
const minimumDimension = 2;
|
|
33
|
+
const maximumDimension = 24;
|
|
31
34
|
|
|
32
|
-
/*** Renders caller-owned
|
|
35
|
+
/*** Renders a configurable caller-owned chess presentation through the shared GridView surface. */
|
|
33
36
|
export const ChessBoard = withZoraThemeScope(ChessBoardInner);
|
|
34
37
|
|
|
35
|
-
/*** Renders
|
|
38
|
+
/*** Renders board state and emits caller-owned cell and move intents without applying chess rules. */
|
|
36
39
|
function ChessBoardInner({
|
|
37
|
-
|
|
40
|
+
columns = 8,
|
|
41
|
+
rows = 8,
|
|
38
42
|
pieces,
|
|
39
43
|
orientation = 'white',
|
|
40
|
-
|
|
41
|
-
legalTargets,
|
|
44
|
+
selectedCell = null,
|
|
45
|
+
legalTargets = [],
|
|
42
46
|
lastMove = null,
|
|
43
47
|
disabled = false,
|
|
44
48
|
showCoordinates = false,
|
|
45
|
-
|
|
49
|
+
resizable = false,
|
|
46
50
|
colorScheme,
|
|
47
|
-
|
|
51
|
+
onCellPress,
|
|
48
52
|
onMoveAttempt,
|
|
49
|
-
|
|
50
|
-
onInvalidMove,
|
|
53
|
+
onDimensionsChange,
|
|
51
54
|
renderPiece,
|
|
52
55
|
interactionPolicy,
|
|
53
56
|
testID,
|
|
54
57
|
}: ChessBoardProps) {
|
|
55
58
|
const { theme } = useZoraTheme();
|
|
56
59
|
const colors = createChessBoardColorScheme(theme, colorScheme);
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
const dimensions = React.useMemo(() => ({ columns, rows }), [columns, rows]);
|
|
61
|
+
const [width, setWidth] = React.useState(0);
|
|
62
|
+
const cells = React.useMemo(
|
|
63
|
+
() => createChessBoardCells(columns, rows, orientation),
|
|
64
|
+
[columns, orientation, rows],
|
|
65
|
+
);
|
|
66
|
+
const piecesByCell = React.useMemo(
|
|
67
|
+
() => new Map((pieces ?? []).map((piece) => [getCellKey(piece.cell), piece])),
|
|
68
|
+
[pieces],
|
|
69
|
+
);
|
|
70
|
+
const cellById = React.useMemo(() => new Map(cells.map((cell) => [cell.id, cell])), [cells]);
|
|
71
|
+
const legalTargetSet = React.useMemo(() => new Set(legalTargets.map(getCellKey)), [legalTargets]);
|
|
72
|
+
const pressCell = createChessBoardCellPressHandler({
|
|
73
|
+
disabled,
|
|
74
|
+
interactionPolicy,
|
|
75
|
+
onCellPress,
|
|
76
|
+
onMoveAttempt,
|
|
77
|
+
selectedCell,
|
|
78
|
+
});
|
|
79
|
+
const canResize =
|
|
80
|
+
resizable && onDimensionsChange !== undefined && !disabled && interactionPolicy !== 'passive';
|
|
81
|
+
const height = width * (dimensions.rows / dimensions.columns);
|
|
82
|
+
const cellSize = width / dimensions.columns;
|
|
76
83
|
|
|
77
|
-
const result = tryMove(fen, attempt);
|
|
78
|
-
if (result) onLegalMove?.(result);
|
|
79
|
-
else onInvalidMove?.(attempt);
|
|
80
|
-
};
|
|
81
84
|
return (
|
|
82
85
|
<View
|
|
83
86
|
accessibilityLabel="Chess board"
|
|
84
|
-
|
|
87
|
+
onLayout={(event) => setWidth(event.nativeEvent.layout.width)}
|
|
88
|
+
style={[
|
|
89
|
+
styles.board,
|
|
90
|
+
{
|
|
91
|
+
aspectRatio: dimensions.columns / dimensions.rows,
|
|
92
|
+
borderColor: colors.border,
|
|
93
|
+
opacity: disabled ? 0.56 : 1,
|
|
94
|
+
},
|
|
95
|
+
]}
|
|
85
96
|
testID={testID}
|
|
86
97
|
>
|
|
87
|
-
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
98
|
+
{width > 0 ? (
|
|
99
|
+
<GridView
|
|
100
|
+
contentHeight={dimensions.rows}
|
|
101
|
+
contentWidth={dimensions.columns}
|
|
102
|
+
defaultViewport={{ pixelsPerUnitX: cellSize, pixelsPerUnitY: cellSize }}
|
|
103
|
+
height={height}
|
|
104
|
+
interactionPolicy="passive"
|
|
105
|
+
items={cells}
|
|
106
|
+
overscanPixels={0}
|
|
107
|
+
renderItem={(item) => {
|
|
108
|
+
const cell = cellById.get(item.id);
|
|
109
|
+
return cell === undefined
|
|
110
|
+
? null
|
|
111
|
+
: renderChessBoardCell({
|
|
112
|
+
cell,
|
|
113
|
+
cellSize,
|
|
114
|
+
colors,
|
|
115
|
+
disabled: disabled || interactionPolicy === 'passive',
|
|
116
|
+
lastMove,
|
|
117
|
+
legalTargetSet,
|
|
118
|
+
onPress: pressCell,
|
|
119
|
+
piece: piecesByCell.get(item.id),
|
|
120
|
+
renderPiece,
|
|
121
|
+
selectedCell,
|
|
122
|
+
showCoordinates,
|
|
123
|
+
testID,
|
|
124
|
+
});
|
|
125
|
+
}}
|
|
126
|
+
width={width}
|
|
127
|
+
/>
|
|
128
|
+
) : null}
|
|
129
|
+
{canResize ? renderChessBoardResizeActions(dimensions, onDimensionsChange, testID) : null}
|
|
130
|
+
</View>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/*** Render one accessible, caller-controlled rectangular board cell. */
|
|
135
|
+
function renderChessBoardCell({
|
|
136
|
+
cell,
|
|
137
|
+
cellSize,
|
|
138
|
+
colors,
|
|
139
|
+
disabled,
|
|
140
|
+
lastMove,
|
|
141
|
+
legalTargetSet,
|
|
142
|
+
onPress,
|
|
143
|
+
piece,
|
|
144
|
+
renderPiece,
|
|
145
|
+
selectedCell,
|
|
146
|
+
showCoordinates,
|
|
147
|
+
testID,
|
|
148
|
+
}: {
|
|
149
|
+
readonly cell: ChessBoardCell & { readonly id: string };
|
|
150
|
+
readonly cellSize: number;
|
|
151
|
+
readonly colors: ReturnType<typeof createChessBoardColorScheme>;
|
|
152
|
+
readonly disabled: boolean;
|
|
153
|
+
readonly lastMove: ChessMoveAttempt | null;
|
|
154
|
+
readonly legalTargetSet: ReadonlySet<string>;
|
|
155
|
+
readonly onPress: (cell: ChessBoardCell) => void;
|
|
156
|
+
readonly piece: ChessPieceState | undefined;
|
|
157
|
+
readonly renderPiece: ChessBoardProps['renderPiece'];
|
|
158
|
+
readonly selectedCell: ChessBoardCell | null;
|
|
159
|
+
readonly showCoordinates: boolean;
|
|
160
|
+
readonly testID: string | undefined;
|
|
161
|
+
}) {
|
|
162
|
+
const light = (cell.column + cell.row) % 2 === 1;
|
|
163
|
+
const key = getCellKey(cell);
|
|
164
|
+
const backgroundColor = cellsEqual(selectedCell, cell)
|
|
165
|
+
? colors.selectedSquare
|
|
166
|
+
: legalTargetSet.has(key)
|
|
167
|
+
? colors.legalTarget
|
|
168
|
+
: cellsEqual(lastMove?.from, cell)
|
|
169
|
+
? colors.lastMoveFrom
|
|
170
|
+
: cellsEqual(lastMove?.to, cell)
|
|
171
|
+
? colors.lastMoveTo
|
|
172
|
+
: light
|
|
173
|
+
? colors.lightSquare
|
|
174
|
+
: colors.darkSquare;
|
|
175
|
+
const pieceContent =
|
|
176
|
+
piece === undefined
|
|
177
|
+
? null
|
|
178
|
+
: renderPiece
|
|
179
|
+
? renderPiece({
|
|
180
|
+
cell,
|
|
181
|
+
color: piece.color === 'white' ? colors.lightPiece : colors.darkPiece,
|
|
182
|
+
piece: piece.piece,
|
|
183
|
+
size: cellSize,
|
|
184
|
+
})
|
|
185
|
+
: (symbols.get(`${piece.color}:${piece.piece.toLowerCase()}`) ?? piece.piece);
|
|
186
|
+
const coordinate = formatCellCoordinate(cell);
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<Pressable
|
|
190
|
+
accessibilityLabel={coordinate}
|
|
191
|
+
accessibilityRole="button"
|
|
192
|
+
accessibilityState={{ disabled }}
|
|
193
|
+
disabled={disabled}
|
|
194
|
+
key={key}
|
|
195
|
+
onPress={() => onPress(cell)}
|
|
196
|
+
style={[styles.square, { backgroundColor }]}
|
|
197
|
+
testID={testID === undefined ? undefined : `${testID}-cell-${coordinate}`}
|
|
198
|
+
>
|
|
199
|
+
{showCoordinates ? (
|
|
200
|
+
<Text
|
|
201
|
+
style={[
|
|
202
|
+
styles.coordinate,
|
|
203
|
+
{ color: light ? colors.lightSquareText : colors.darkSquareText },
|
|
204
|
+
]}
|
|
205
|
+
>
|
|
206
|
+
{coordinate}
|
|
207
|
+
</Text>
|
|
208
|
+
) : null}
|
|
209
|
+
{piece === undefined ? null : (
|
|
210
|
+
<View pointerEvents="none" style={styles.pieceContainer}>
|
|
211
|
+
{renderPiece ? (
|
|
212
|
+
pieceContent
|
|
213
|
+
) : (
|
|
214
|
+
<Text
|
|
215
|
+
style={[
|
|
216
|
+
styles.piece,
|
|
217
|
+
{
|
|
108
218
|
color: piece.color === 'white' ? colors.lightPiece : colors.darkPiece,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
219
|
+
fontSize: cellSize * 0.58,
|
|
220
|
+
lineHeight: cellSize * 0.7,
|
|
221
|
+
},
|
|
222
|
+
]}
|
|
223
|
+
>
|
|
224
|
+
{pieceContent}
|
|
225
|
+
</Text>
|
|
226
|
+
)}
|
|
227
|
+
</View>
|
|
228
|
+
)}
|
|
229
|
+
</Pressable>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/*** Render bounded editor actions only when the caller explicitly enables dimension editing. */
|
|
234
|
+
function renderChessBoardResizeActions(
|
|
235
|
+
dimensions: ChessBoardDimensions,
|
|
236
|
+
onDimensionsChange: (dimensions: ChessBoardDimensions) => void,
|
|
237
|
+
testID: string | undefined,
|
|
238
|
+
) {
|
|
239
|
+
return (
|
|
240
|
+
<View accessibilityLabel="Chess board dimensions" style={styles.resizeActions}>
|
|
241
|
+
{renderResizeAction(
|
|
242
|
+
'Add row',
|
|
243
|
+
{ ...dimensions, rows: dimensions.rows + 1 },
|
|
244
|
+
onDimensionsChange,
|
|
245
|
+
dimensions.rows < maximumDimension,
|
|
246
|
+
testID,
|
|
247
|
+
)}
|
|
248
|
+
{renderResizeAction(
|
|
249
|
+
'Remove row',
|
|
250
|
+
{ ...dimensions, rows: dimensions.rows - 1 },
|
|
251
|
+
onDimensionsChange,
|
|
252
|
+
dimensions.rows > minimumDimension,
|
|
253
|
+
testID,
|
|
254
|
+
)}
|
|
255
|
+
{renderResizeAction(
|
|
256
|
+
'Add column',
|
|
257
|
+
{ ...dimensions, columns: dimensions.columns + 1 },
|
|
258
|
+
onDimensionsChange,
|
|
259
|
+
dimensions.columns < maximumDimension,
|
|
260
|
+
testID,
|
|
261
|
+
)}
|
|
262
|
+
{renderResizeAction(
|
|
263
|
+
'Remove column',
|
|
264
|
+
{ ...dimensions, columns: dimensions.columns - 1 },
|
|
265
|
+
onDimensionsChange,
|
|
266
|
+
dimensions.columns > minimumDimension,
|
|
267
|
+
testID,
|
|
268
|
+
)}
|
|
152
269
|
</View>
|
|
153
270
|
);
|
|
154
271
|
}
|
|
155
272
|
|
|
273
|
+
/*** Render one caller-controlled dimension-change action. */
|
|
274
|
+
function renderResizeAction(
|
|
275
|
+
label: string,
|
|
276
|
+
dimensions: ChessBoardDimensions,
|
|
277
|
+
onDimensionsChange: (dimensions: ChessBoardDimensions) => void,
|
|
278
|
+
enabled: boolean,
|
|
279
|
+
testID: string | undefined,
|
|
280
|
+
) {
|
|
281
|
+
return (
|
|
282
|
+
<Pressable
|
|
283
|
+
accessibilityLabel={label}
|
|
284
|
+
accessibilityRole="button"
|
|
285
|
+
disabled={!enabled}
|
|
286
|
+
onPress={() => onDimensionsChange(dimensions)}
|
|
287
|
+
testID={
|
|
288
|
+
testID === undefined ? undefined : `${testID}-${label.toLowerCase().replace(' ', '-')}`
|
|
289
|
+
}
|
|
290
|
+
>
|
|
291
|
+
<Text>{label}</Text>
|
|
292
|
+
</Pressable>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/*** Compares optional cell coordinates without attaching chess-rule meaning to them. */
|
|
297
|
+
function cellsEqual(
|
|
298
|
+
left: ChessBoardCell | undefined | null,
|
|
299
|
+
right: ChessBoardCell | undefined | null,
|
|
300
|
+
): boolean {
|
|
301
|
+
if (!left || !right) return false;
|
|
302
|
+
return left.column === right.column && left.row === right.row;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/*** Format a stable display label for a bounded board cell. */
|
|
306
|
+
function formatCellCoordinate(cell: ChessBoardCell): string {
|
|
307
|
+
return `${String.fromCharCode(96 + cell.column)}${cell.row}`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/*** Create a stable generic identity from caller-owned row and column values. */
|
|
311
|
+
function getCellKey(cell: ChessBoardCell): string {
|
|
312
|
+
return `${cell.column}:${cell.row}`;
|
|
313
|
+
}
|
|
314
|
+
|
|
156
315
|
const styles = StyleSheet.create({
|
|
157
316
|
board: {
|
|
158
|
-
aspectRatio: 1,
|
|
159
317
|
borderRadius: 12,
|
|
160
318
|
borderWidth: StyleSheet.hairlineWidth,
|
|
161
|
-
flexDirection: 'row',
|
|
162
|
-
flexWrap: 'wrap',
|
|
163
319
|
overflow: 'hidden',
|
|
164
320
|
width: '100%',
|
|
165
321
|
},
|
|
@@ -172,7 +328,7 @@ const styles = StyleSheet.create({
|
|
|
172
328
|
top: 2,
|
|
173
329
|
zIndex: 2,
|
|
174
330
|
},
|
|
175
|
-
piece: {
|
|
331
|
+
piece: { fontWeight: '600' },
|
|
176
332
|
pieceContainer: {
|
|
177
333
|
alignItems: 'center',
|
|
178
334
|
bottom: 0,
|
|
@@ -182,11 +338,6 @@ const styles = StyleSheet.create({
|
|
|
182
338
|
right: 0,
|
|
183
339
|
top: 0,
|
|
184
340
|
},
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
aspectRatio: 1,
|
|
188
|
-
width: '12.5%',
|
|
189
|
-
justifyContent: 'center',
|
|
190
|
-
position: 'relative',
|
|
191
|
-
},
|
|
341
|
+
resizeActions: { flexDirection: 'row', gap: 8, padding: 8 },
|
|
342
|
+
square: { alignItems: 'center', justifyContent: 'center', position: 'relative' },
|
|
192
343
|
});
|