@connectorvol/chess-widgets 9.0.0 → 9.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/dist/(components)/BoardSettingsTrigger.svelte +10 -0
- package/dist/(components)/BoardSettingsTrigger.svelte.d.ts +18 -0
- package/dist/game-analyzer/GameAnalyzer.svelte +88 -74
- package/dist/game-analyzer/gameAnalyzer.svelte.js +2 -7
- package/dist/game-analyzer/types.d.ts +3 -6
- package/dist/index.d.ts +1 -1
- package/dist/puzzle/puzzlePreviewPathNags.js +1 -1
- package/dist/puzzle-creation/PuzzleBoardTreeViewerPane.svelte +199 -171
- package/dist/puzzle-creation/PuzzleBoardTreeViewerPane.svelte.d.ts +7 -3
- package/dist/puzzle-creation/PuzzleCreationWizard.svelte +184 -180
- package/dist/puzzle-creation/PuzzlePgnBoardTreeEditor.svelte +906 -870
- package/dist/puzzle-creation/StepMoves.svelte +209 -207
- package/dist/puzzle-creation/StepMoves.svelte.d.ts +1 -2
- package/dist/puzzle-creation/StepPosition.svelte +22 -2
- package/dist/puzzle-creation/puzzleWizardState.js +1 -1
- package/dist/puzzle-creation/types.d.ts +0 -4
- package/package.json +12 -10
|
@@ -11,8 +11,11 @@ interface Props {
|
|
|
11
11
|
chessboard: BoardApi;
|
|
12
12
|
/**
|
|
13
13
|
* Возвращает снимок дизайна, передаваемый в `<Chessboard design={...} />`.
|
|
14
|
+
* Опционально: если не передан, доска читает дизайн из контекста
|
|
15
|
+
* (`setBoardDesignSettingsContext`), что позволяет реактивно подхватывать
|
|
16
|
+
* изменения из `<BoardSettings />`.
|
|
14
17
|
*/
|
|
15
|
-
chessboardDesign
|
|
18
|
+
chessboardDesign?: TChessBoardDesignSettings;
|
|
16
19
|
/**
|
|
17
20
|
* Возвращает экземпляр дерева ходов для `TreeViewer`.
|
|
18
21
|
*/
|
|
@@ -47,8 +50,9 @@ interface Props {
|
|
|
47
50
|
*/
|
|
48
51
|
showPuzzleBranchNags?: boolean;
|
|
49
52
|
/**
|
|
50
|
-
* Возвращает тему `TreeViewer` (фон, границы, текст).
|
|
51
|
-
*
|
|
53
|
+
* Возвращает тему `TreeViewer` (фон, границы, текст). По умолчанию
|
|
54
|
+
* подстраивается под `mode-watcher` (dark → `TREE_VIEWER_DARK_THEME`,
|
|
55
|
+
* иначе `TREE_VIEWER_LIGHT_THEME`).
|
|
52
56
|
*/
|
|
53
57
|
theme?: TTreeViewerTheme;
|
|
54
58
|
/**
|
|
@@ -1,202 +1,206 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
export type { TPuzzleCreationWizardProps } from "./types.js";
|
|
3
|
+
export type {
|
|
4
|
+
TPuzzleWizardCoreState,
|
|
5
|
+
TPuzzleWizardState,
|
|
6
|
+
} from "./puzzleWizardState.js";
|
|
7
7
|
</script>
|
|
8
8
|
|
|
9
9
|
<script lang="ts" generics="S extends TPuzzleWizardCoreState">
|
|
10
|
-
|
|
10
|
+
import type { Snippet } from "svelte";
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
import { Wizard } from "@connectorvol/shared";
|
|
13
|
+
import type { TWizardStep, TWizardStepContext } from "@connectorvol/shared";
|
|
14
|
+
import StepMoves from "./StepMoves.svelte";
|
|
15
|
+
import StepPosition from "./StepPosition.svelte";
|
|
16
|
+
import StepPreview from "./StepPreview.svelte";
|
|
17
|
+
import type { TPuzzleCreatedPayload } from "../puzzle/puzzleCreatedPayload.js";
|
|
18
|
+
import type { TPuzzleWizardCoreState } from "./puzzleWizardState.js";
|
|
19
|
+
import { PUZZLE_WIZARD_CORE_STEPS } from "./puzzleWizardState.js";
|
|
20
|
+
import { createEmptyTreeFromFen } from "../puzzle/puzzleData.js";
|
|
21
|
+
import { PgnOps } from "@connectorvol/chessops/pgnOps.svelte";
|
|
22
|
+
import { ChessTree, createPgnFromTree } from "@connectorvol/tree";
|
|
23
|
+
import {
|
|
24
|
+
CHESSBOARD_THEMES,
|
|
25
|
+
Draggable,
|
|
26
|
+
type ChessboardTheme,
|
|
27
|
+
type IChessBoardActions,
|
|
28
|
+
} from "@connectorvol/chessboard";
|
|
29
|
+
import { calculatePly, Color, Square } from "@connectorvol/shared";
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
import { createPuzzleLineEditingBoardApi } from "./createPuzzleLineEditingBoard.js";
|
|
32
|
+
import { syncPuzzleBranchNagsOnTree } from "../puzzle/syncPuzzleBranchNags.js";
|
|
33
|
+
import { DEFAULT_BOARD_APPEARANCE_SETTINGS } from "../constants/default-board-appearance-settings.js";
|
|
34
|
+
import type { TChessboardAppearanceSettings } from "./types.js";
|
|
35
|
+
import { derived } from "svelte/store";
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
37
|
+
interface Props {
|
|
38
|
+
/** Возвращает общий state визарда (двухсторонняя привязка). */
|
|
39
|
+
wizardState: S;
|
|
40
|
+
/** Возвращает колбэк завершения с шага превью без доп. шагов. */
|
|
41
|
+
onPuzzleCreated: (payload: TPuzzleCreatedPayload) => void;
|
|
42
|
+
/** Возвращает колбэк завершения с доп. шага (`wizard.done()`). */
|
|
43
|
+
onDone?: (state: S) => void;
|
|
44
|
+
/** Возвращает seed FEN для сброса шага визарда при изменении. */
|
|
45
|
+
fen?: string;
|
|
46
|
+
/** Возвращает тему оформления шахматной доски. */
|
|
47
|
+
boardTheme?: ChessboardTheme;
|
|
48
|
+
/** Возвращает визуальные настройки доски. */
|
|
49
|
+
boardAppearanceSettings?: TChessboardAppearanceSettings;
|
|
50
|
+
/** Возвращает дополнительные шаги после превью. */
|
|
51
|
+
additionalSteps?: readonly TWizardStep[];
|
|
52
|
+
/** Возвращает snippet дополнительных шагов. */
|
|
53
|
+
additionalStep?: Snippet<[TWizardStepContext<S>]>;
|
|
54
|
+
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
let {
|
|
57
|
+
wizardState = $bindable(),
|
|
58
|
+
onPuzzleCreated,
|
|
59
|
+
onDone,
|
|
60
|
+
fen: fenProp,
|
|
61
|
+
boardTheme,
|
|
62
|
+
boardAppearanceSettings = DEFAULT_BOARD_APPEARANCE_SETTINGS,
|
|
63
|
+
additionalSteps = [],
|
|
64
|
+
additionalStep,
|
|
65
|
+
}: Props = $props();
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
const hasAdditionalSteps = $derived(additionalSteps.length > 0);
|
|
68
|
+
const steps = $derived([...PUZZLE_WIZARD_CORE_STEPS, ...additionalSteps]);
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const move = chess.makeSanMove(san);
|
|
78
|
-
if (!move) return;
|
|
79
|
-
const fen = chess.fen();
|
|
80
|
-
const { halfMoves, fullMoves } = calculatePly(fen);
|
|
81
|
-
tree.addNodeToCurrent({
|
|
82
|
-
id: "",
|
|
83
|
-
children: [],
|
|
84
|
-
data: {
|
|
85
|
-
fen,
|
|
86
|
-
san,
|
|
87
|
-
ply: halfMoves,
|
|
88
|
-
fullMoves,
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
return { move, fen, turn: chess.turn() };
|
|
92
|
-
};
|
|
70
|
+
let chess = $derived(
|
|
71
|
+
new PgnOps(wizardState.puzzleData.initialFen, "chess"),
|
|
72
|
+
);
|
|
73
|
+
let tree = $derived(
|
|
74
|
+
new ChessTree(
|
|
75
|
+
createEmptyTreeFromFen(wizardState.puzzleData.initialFen),
|
|
76
|
+
),
|
|
77
|
+
);
|
|
93
78
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
beforePieceMoveSan(san: string) {
|
|
98
|
-
const result = addMoveToTree(san);
|
|
99
|
-
return result;
|
|
100
|
-
},
|
|
101
|
-
afterPieceMoveSan: () => {},
|
|
102
|
-
beforePieceMove: (from, to, promotion) => {
|
|
103
|
-
const san = chess.getSanForMove({ from, to, promotion });
|
|
104
|
-
chess.makeMove({ from, to, promotion });
|
|
79
|
+
const addMoveToTree = (san: string) => {
|
|
80
|
+
const move = chess.makeSanMove(san);
|
|
81
|
+
if (!move) return;
|
|
105
82
|
const fen = chess.fen();
|
|
106
83
|
const { halfMoves, fullMoves } = calculatePly(fen);
|
|
107
84
|
tree.addNodeToCurrent({
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
85
|
+
id: "",
|
|
86
|
+
children: [],
|
|
87
|
+
data: {
|
|
88
|
+
fen,
|
|
89
|
+
san,
|
|
90
|
+
ply: halfMoves,
|
|
91
|
+
fullMoves,
|
|
92
|
+
},
|
|
116
93
|
});
|
|
117
|
-
return fen;
|
|
118
|
-
|
|
119
|
-
afterPieceMove: () => {
|
|
120
|
-
const side = chess.turn();
|
|
121
|
-
chessboardApi.draggable =
|
|
122
|
-
side === Color.WHITE ? Draggable.WHITE : Draggable.BLACK;
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
};
|
|
94
|
+
return { move, fen, turn: chess.turn() };
|
|
95
|
+
};
|
|
126
96
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
97
|
+
const actions: IChessBoardActions = {
|
|
98
|
+
game: {
|
|
99
|
+
possibleMovesOnSquare: (square: Square) => chess.moves(square),
|
|
100
|
+
beforePieceMoveSan(san: string) {
|
|
101
|
+
const result = addMoveToTree(san);
|
|
102
|
+
return result;
|
|
103
|
+
},
|
|
104
|
+
afterPieceMoveSan: () => {},
|
|
105
|
+
beforePieceMove: (from, to, promotion) => {
|
|
106
|
+
const san = chess.getSanForMove({ from, to, promotion });
|
|
107
|
+
chess.makeMove({ from, to, promotion });
|
|
108
|
+
const fen = chess.fen();
|
|
109
|
+
const { halfMoves, fullMoves } = calculatePly(fen);
|
|
110
|
+
tree.addNodeToCurrent({
|
|
111
|
+
id: "",
|
|
112
|
+
children: [],
|
|
113
|
+
data: {
|
|
114
|
+
fen,
|
|
115
|
+
san,
|
|
116
|
+
ply: halfMoves,
|
|
117
|
+
fullMoves,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
return fen;
|
|
121
|
+
},
|
|
122
|
+
afterPieceMove: () => {
|
|
123
|
+
const side = chess.turn();
|
|
124
|
+
chessboardApi.draggable =
|
|
125
|
+
side === Color.WHITE ? Draggable.WHITE : Draggable.BLACK;
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
136
129
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Представляет сборку доски для шага построения линии: позиция и ориентация по стороне хода в FEN.
|
|
132
|
+
*/
|
|
133
|
+
function createMainChessboard(fullFen: string) {
|
|
134
|
+
return createPuzzleLineEditingBoardApi(fullFen, actions, {
|
|
135
|
+
boardTheme: boardTheme ?? CHESSBOARD_THEMES.blue,
|
|
136
|
+
boardAppearanceSettings,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
142
139
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
*/
|
|
146
|
-
function handleMovesNext(moves: string[]) {
|
|
147
|
-
wizardState.puzzleData.moves = moves;
|
|
148
|
-
syncPuzzleBranchNagsOnTree(
|
|
149
|
-
tree,
|
|
150
|
-
wizardState.puzzleData.initialFen.trim().split(/\s+/)[1] === "b"
|
|
151
|
-
? Color.BLACK
|
|
152
|
-
: Color.WHITE,
|
|
140
|
+
let chessboard = $derived(
|
|
141
|
+
createMainChessboard(wizardState.puzzleData.initialFen),
|
|
153
142
|
);
|
|
154
|
-
|
|
155
|
-
|
|
143
|
+
let chessboardApi = $derived(chessboard.api);
|
|
144
|
+
|
|
145
|
+
// ponytail: компонент только читает контекст дизайна. Дизайн для доски шага 2,
|
|
146
|
+
// который раньше поднимался через `setBoardDesignSettingsContext`, теперь
|
|
147
|
+
// пробрасывается явно пропом `chessboardDesign` в `<StepMoves />`.
|
|
148
|
+
const chessboardDesign = $derived(chessboard.design);
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Представляет переход со шага построения линии на превью.
|
|
152
|
+
*/
|
|
153
|
+
function handleMovesNext(moves: string[]) {
|
|
154
|
+
wizardState.puzzleData.moves = moves;
|
|
155
|
+
syncPuzzleBranchNagsOnTree(
|
|
156
|
+
tree,
|
|
157
|
+
wizardState.puzzleData.initialFen.trim().split(/\s+/)[1] === "b"
|
|
158
|
+
? Color.BLACK
|
|
159
|
+
: Color.WHITE,
|
|
160
|
+
);
|
|
161
|
+
wizardState.solutionPgn = createPgnFromTree(tree.rootNode);
|
|
162
|
+
}
|
|
156
163
|
</script>
|
|
157
164
|
|
|
158
|
-
<Wizard
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
{
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
{
|
|
199
|
-
{@render additionalStep(w)}
|
|
200
|
-
{/if}
|
|
201
|
-
{/snippet}
|
|
165
|
+
<Wizard bind:wizardState {steps} resetSignal={fenProp} {onDone}>
|
|
166
|
+
{#snippet children(w)}
|
|
167
|
+
{#if w.currentStep === 1}
|
|
168
|
+
<StepPosition
|
|
169
|
+
initialFen={w.state.puzzleData.initialFen}
|
|
170
|
+
onNext={(fen) => {
|
|
171
|
+
w.state.puzzleData.initialFen = fen;
|
|
172
|
+
w.next();
|
|
173
|
+
}}
|
|
174
|
+
{boardTheme}
|
|
175
|
+
{boardAppearanceSettings}
|
|
176
|
+
/>
|
|
177
|
+
{:else if w.currentStep === 2}
|
|
178
|
+
<StepMoves
|
|
179
|
+
puzzleData={w.state.puzzleData}
|
|
180
|
+
{chess}
|
|
181
|
+
{tree}
|
|
182
|
+
chessboard={chessboardApi}
|
|
183
|
+
{chessboardDesign}
|
|
184
|
+
onBack={w.back}
|
|
185
|
+
onNext={(moves) => {
|
|
186
|
+
handleMovesNext(moves);
|
|
187
|
+
w.next();
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
{:else if w.currentStep === 3}
|
|
191
|
+
<StepPreview
|
|
192
|
+
puzzleData={w.state.puzzleData}
|
|
193
|
+
solutionPgn={w.state.solutionPgn}
|
|
194
|
+
onBack={w.back}
|
|
195
|
+
onNext={hasAdditionalSteps ? w.next : undefined}
|
|
196
|
+
onPuzzleCreated={hasAdditionalSteps
|
|
197
|
+
? undefined
|
|
198
|
+
: onPuzzleCreated}
|
|
199
|
+
{boardTheme}
|
|
200
|
+
{boardAppearanceSettings}
|
|
201
|
+
/>
|
|
202
|
+
{:else if additionalStep}
|
|
203
|
+
{@render additionalStep(w)}
|
|
204
|
+
{/if}
|
|
205
|
+
{/snippet}
|
|
202
206
|
</Wizard>
|