@connectorvol/shared 8.0.1 → 9.0.0

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/index.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  export { Color } from "./color.js";
2
2
  export { DEFAULT_PIECE_SET } from "./defaultSet.js";
3
3
  export { generateId } from "./generateId.js";
4
+ export { pieceGlyph } from "./pieceGlyph.js";
4
5
  export { PieceType } from "./pieceType.js";
5
6
  export { Square } from "./square.js";
6
7
  export { type PieceSet } from "./pieceSet.js";
7
8
  export { type Move } from "./move.js";
8
9
  export { calculatePly } from "./calculatePly.js";
9
- export { MOVE_EVALUATION_NAG_IDS, NOVELTY_NAG_ID, PUZZLE_BRANCH_CORRECT_NAG_ID, PUZZLE_BRANCH_NAG_IDS, PUZZLE_BRANCH_WRONG_NAG_ID, type TNagMoveBoardGlyph, type TSplitMoveEvaluationNagsForBoard, isMoveEvaluationNag, isPuzzleBranchNag, moveEvaluationNagBoardGlyph, nagBadgeBackground, pickFirstMoveEvaluationNag, splitMoveEvaluationNagsForBoard, transformNag, } from "./nagGlyphs.js";
10
+ export { MOVE_EVALUATION_NAG_IDS, NOVELTY_NAG_ID, PUZZLE_BRANCH_CORRECT_NAG_ID, PUZZLE_BRANCH_NAG_IDS, PUZZLE_BRANCH_WRONG_NAG_ID, type TNagMoveBoardGlyph, type TSplitMoveEvaluationNagsForBoard, isMoveEvaluationNag, isPuzzleBranchNag, moveEvaluationNagBoardGlyph, nagBadgeBackground, nagBoardGlyph, pickFirstMoveEvaluationNag, pickFirstPuzzleBranchNag, splitMoveEvaluationNagsForBoard, transformNag, } from "./nagGlyphs.js";
11
+ export { PUZZLE_OPENING_TAGS, PUZZLE_TACTIC_TAGS, PUZZLE_TACTIC_TAGS_MAX, type TPuzzleOpeningTagOption, type TPuzzleTagOption, } from "./puzzleTagCatalog.js";
12
+ export { default as Wizard } from "./wizard/Wizard.svelte";
13
+ export { getWizardContext, setWizardContext, type TWizardStep, type TWizardStepContext, } from "./wizard/wizardContext.js";
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  export { Color } from "./color.js";
2
2
  export { DEFAULT_PIECE_SET } from "./defaultSet.js";
3
3
  export { generateId } from "./generateId.js";
4
+ export { pieceGlyph } from "./pieceGlyph.js";
4
5
  export { PieceType } from "./pieceType.js";
5
6
  export { Square } from "./square.js";
6
7
  export {} from "./pieceSet.js";
7
8
  export {} from "./move.js";
8
9
  export { calculatePly } from "./calculatePly.js";
9
- export { MOVE_EVALUATION_NAG_IDS, NOVELTY_NAG_ID, PUZZLE_BRANCH_CORRECT_NAG_ID, PUZZLE_BRANCH_NAG_IDS, PUZZLE_BRANCH_WRONG_NAG_ID, isMoveEvaluationNag, isPuzzleBranchNag, moveEvaluationNagBoardGlyph, nagBadgeBackground, pickFirstMoveEvaluationNag, splitMoveEvaluationNagsForBoard, transformNag, } from "./nagGlyphs.js";
10
+ export { MOVE_EVALUATION_NAG_IDS, NOVELTY_NAG_ID, PUZZLE_BRANCH_CORRECT_NAG_ID, PUZZLE_BRANCH_NAG_IDS, PUZZLE_BRANCH_WRONG_NAG_ID, isMoveEvaluationNag, isPuzzleBranchNag, moveEvaluationNagBoardGlyph, nagBadgeBackground, nagBoardGlyph, pickFirstMoveEvaluationNag, pickFirstPuzzleBranchNag, splitMoveEvaluationNagsForBoard, transformNag, } from "./nagGlyphs.js";
11
+ export { PUZZLE_OPENING_TAGS, PUZZLE_TACTIC_TAGS, PUZZLE_TACTIC_TAGS_MAX, } from "./puzzleTagCatalog.js";
12
+ export { default as Wizard } from "./wizard/Wizard.svelte";
13
+ export { getWizardContext, setWizardContext, } from "./wizard/wizardContext.js";
@@ -36,5 +36,9 @@ export declare function splitMoveEvaluationNagsForBoard(nags: readonly number[]
36
36
  export declare function nagBadgeBackground(nag: number): string;
37
37
  /** Представляет преобразование номера NAG в строку для UI (как в меню Lichess). */
38
38
  export declare function transformNag(nag: number | undefined): string;
39
+ /** Представляет первый NAG из списка, относящийся к паре «верно / неверно» для ветки задачи. */
40
+ export declare function pickFirstPuzzleBranchNag(nags: readonly number[] | undefined): number | undefined;
41
+ /** Представляет глиф и фон для бейджа NAG оценки хода или ветки задачи на клетке `to`. */
42
+ export declare function nagBoardGlyph(nag: number): TNagMoveBoardGlyph | null;
39
43
  /** Представляет глиф и фон для бейджа оценки хода на клетке `to` или null, если NAG не из этой группы. */
40
44
  export declare function moveEvaluationNagBoardGlyph(nag: number): TNagMoveBoardGlyph | null;
package/dist/nagGlyphs.js CHANGED
@@ -126,12 +126,28 @@ export function transformNag(nag) {
126
126
  return symbol;
127
127
  return `$${nag}`;
128
128
  }
129
- /** Представляет глиф и фон для бейджа оценки хода на клетке `to` или null, если NAG не из этой группы. */
130
- export function moveEvaluationNagBoardGlyph(nag) {
131
- if (!isMoveEvaluationNag(nag))
129
+ /** Представляет первый NAG из списка, относящийся к паре «верно / неверно» для ветки задачи. */
130
+ export function pickFirstPuzzleBranchNag(nags) {
131
+ if (!nags?.length)
132
+ return undefined;
133
+ for (const n of nags) {
134
+ if (isPuzzleBranchNag(n))
135
+ return n;
136
+ }
137
+ return undefined;
138
+ }
139
+ /** Представляет глиф и фон для бейджа NAG оценки хода или ветки задачи на клетке `to`. */
140
+ export function nagBoardGlyph(nag) {
141
+ if (!isMoveEvaluationNag(nag) && !isPuzzleBranchNag(nag))
132
142
  return null;
133
143
  return {
134
144
  background: nagBadgeBackground(nag),
135
145
  label: transformNag(nag) || `$${nag}`,
136
146
  };
137
147
  }
148
+ /** Представляет глиф и фон для бейджа оценки хода на клетке `to` или null, если NAG не из этой группы. */
149
+ export function moveEvaluationNagBoardGlyph(nag) {
150
+ if (!isMoveEvaluationNag(nag))
151
+ return null;
152
+ return nagBoardGlyph(nag);
153
+ }
@@ -0,0 +1,3 @@
1
+ import { Color } from "./color.js";
2
+ import { PieceType } from "./pieceType.js";
3
+ export declare function pieceGlyph(pieceType: PieceType, color: Color): string;
@@ -0,0 +1,18 @@
1
+ import { Color } from "./color.js";
2
+ import { PieceType } from "./pieceType.js";
3
+ /**
4
+ * Возвращает Unicode-глиф шахматной фигуры для использования в SAN-нотации.
5
+ * Белые фигуры — залитые (♔♕♖♗♘♙), чёрные — контурные (♚♛♜♝♞♟).
6
+ * Замена SVG-сниппетов: текстовый символ выравнивается по baseline как обычная буква.
7
+ */
8
+ const GLYPHS = {
9
+ [PieceType.KING]: { [Color.WHITE]: "♔", [Color.BLACK]: "♚" },
10
+ [PieceType.QUEEN]: { [Color.WHITE]: "♕", [Color.BLACK]: "♛" },
11
+ [PieceType.ROOK]: { [Color.WHITE]: "♖", [Color.BLACK]: "♜" },
12
+ [PieceType.BISHOP]: { [Color.WHITE]: "♗", [Color.BLACK]: "♝" },
13
+ [PieceType.KNIGHT]: { [Color.WHITE]: "♘", [Color.BLACK]: "♞" },
14
+ [PieceType.PAWN]: { [Color.WHITE]: "♙", [Color.BLACK]: "♟" },
15
+ };
16
+ export function pieceGlyph(pieceType, color) {
17
+ return GLYPHS[pieceType][color];
18
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Представляет элемент каталога тегов задачи (идентификатор и подпись для UI).
3
+ */
4
+ export interface TPuzzleTagOption {
5
+ /**
6
+ * Возвращает стабильный идентификатор тега.
7
+ */
8
+ id: string;
9
+ /**
10
+ * Возвращает отображаемое название тега.
11
+ */
12
+ label: string;
13
+ }
14
+ /**
15
+ * Представляет дебютный тег с FEN типовой позиции для превью при наведении.
16
+ */
17
+ export interface TPuzzleOpeningTagOption extends TPuzzleTagOption {
18
+ /**
19
+ * Возвращает полный FEN типовой позиции варианта.
20
+ */
21
+ fen: string;
22
+ }
23
+ /**
24
+ * Представляет популярные дебюты для выбора одного тега.
25
+ */
26
+ export declare const PUZZLE_OPENING_TAGS: readonly TPuzzleOpeningTagOption[];
27
+ /**
28
+ * Представляет каталог тактических приёмов для выбора до трёх тегов.
29
+ */
30
+ export declare const PUZZLE_TACTIC_TAGS: readonly TPuzzleTagOption[];
31
+ /** Возвращает максимальное число выбираемых тактических тегов. */
32
+ export declare const PUZZLE_TACTIC_TAGS_MAX = 3;
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Представляет популярные дебюты для выбора одного тега.
3
+ */
4
+ export const PUZZLE_OPENING_TAGS = [
5
+ {
6
+ id: "sicilian-najdorf",
7
+ label: "Сицилианская: Найдорф",
8
+ fen: "rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6",
9
+ },
10
+ {
11
+ id: "sicilian-dragon",
12
+ label: "Сицилианская: дракон",
13
+ fen: "rnbqkb1r/pp2pp1p/3p1np1/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6",
14
+ },
15
+ {
16
+ id: "sicilian-chelyabinsk",
17
+ label: "Сицилианская: челябинский вариант",
18
+ fen: "r1bqkb1r/pp1p1ppp/2n2n2/4p3/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6",
19
+ },
20
+ {
21
+ id: "sicilian-classical",
22
+ label: "Сицилианская: классический вариант",
23
+ fen: "r1bqkb1r/pp2pppp/2np1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 3 6",
24
+ },
25
+ {
26
+ id: "sicilian-alapin",
27
+ label: "Сицилианская: вариант Алапина",
28
+ fen: "rnbqkbnr/pp1ppppp/8/2p5/4P3/2P5/PP1P1PPP/RNBQKBNR b KQkq - 0 2",
29
+ },
30
+ {
31
+ id: "sicilian-rossolimo",
32
+ label: "Сицилианская: вариант Россолимо",
33
+ fen: "r1bqkbnr/pp1ppppp/2n5/1Bp5/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3",
34
+ },
35
+ {
36
+ id: "caro-kann",
37
+ label: "Каро-Канн",
38
+ fen: "rn1qkbnr/pp2pppp/2p5/5b2/3PN3/8/PPP2PPP/R1BQKBNR w KQkq - 1 5",
39
+ },
40
+ {
41
+ id: "french-defense",
42
+ label: "Французская защита",
43
+ fen: "rnbqkb1r/ppp2ppp/4pn2/3p4/3PP3/2N5/PPP2PPP/R1BQKBNR w KQkq - 2 4",
44
+ },
45
+ {
46
+ id: "nimzo-indian",
47
+ label: "Защита Нимцовича",
48
+ fen: "rnbqk2r/pppp1ppp/4pn2/8/1bPP4/2N5/PP2PPPP/R1BQKBNR w KQkq - 2 4",
49
+ },
50
+ {
51
+ id: "ruy-lopez",
52
+ label: "Испанская партия (Руй-Лопес)",
53
+ fen: "r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 4",
54
+ },
55
+ {
56
+ id: "italian-game",
57
+ label: "Итальянская партия",
58
+ fen: "r1bqk1nr/pppp1ppp/2n5/2b1p3/2B1P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 4 4",
59
+ },
60
+ {
61
+ id: "english-opening",
62
+ label: "Английское начало",
63
+ fen: "rnbqkb1r/pppp1ppp/5n2/4p3/2P5/2N5/PP1PPPPP/R1BQKBNR w KQkq - 2 3",
64
+ },
65
+ {
66
+ id: "grunfeld-defense",
67
+ label: "Защита Грюнфельда",
68
+ fen: "rnbqkb1r/ppp1pp1p/5np1/3p4/2PP4/2N5/PP2PPPP/R1BQKBNR w KQkq - 0 4",
69
+ },
70
+ {
71
+ id: "slav-defense",
72
+ label: "Славянская защита",
73
+ fen: "rn1qkb1r/pp2pppp/2p2n2/3p1b2/2PP4/2N2N2/PP2PPPP/R1BQKB1R w KQkq - 4 5",
74
+ },
75
+ {
76
+ id: "london-system",
77
+ label: "Система Лондона",
78
+ fen: "rnbqkb1r/pp3ppp/4pn2/2pp4/3P1B2/4PN2/PPP2PPP/RN1QKB1R w KQkq - 0 5",
79
+ },
80
+ {
81
+ id: "scotch-game",
82
+ label: "Шотландская партия",
83
+ fen: "r1bqkbnr/pppp1ppp/2n5/8/3NP3/8/PPP2PPP/RNBQKB1R b KQkq - 0 4",
84
+ },
85
+ {
86
+ id: "scandinavian-defense",
87
+ label: "Скандинавская защита",
88
+ fen: "rnb1kbnr/ppp1pppp/8/q7/8/2N5/PPPP1PPP/R1BQKBNR w KQkq - 2 4",
89
+ },
90
+ {
91
+ id: "queens-gambit",
92
+ label: "Ферзевый гамбит",
93
+ fen: "rnbqkb1r/ppp2ppp/4pn2/3p2B1/2PP4/2N5/PP2PPPP/R2QKBNR b KQkq - 3 4",
94
+ },
95
+ {
96
+ id: "queens-gambit-declined",
97
+ label: "Ферзевый гамбит отказанный",
98
+ fen: "rnbqk2r/ppp1bppp/4pn2/3p2B1/2PP4/2N5/PP2PPPP/R2QKBNR w KQkq - 4 5",
99
+ },
100
+ {
101
+ id: "indian-defense",
102
+ label: "Индийская защита",
103
+ fen: "rnbqk2r/ppppppbp/5np1/8/2PP4/2N5/PP2PPPP/R1BQKBNR w KQkq - 2 4",
104
+ },
105
+ {
106
+ id: "kings-indian-defense",
107
+ label: "Индийская защита короля",
108
+ fen: "rnbq1rk1/ppp1ppbp/3p1np1/8/2PPP3/2N2N2/PP3PPP/R1BQKB1R w KQ - 2 6",
109
+ },
110
+ {
111
+ id: "alekhine-defense",
112
+ label: "Защита Алехина",
113
+ fen: "rnbqkb1r/ppp1pppp/3p4/3nP3/3P4/5N2/PPP2PPP/RNBQKB1R b KQkq - 1 4",
114
+ },
115
+ {
116
+ id: "old-indian-defense",
117
+ label: "Староиндийская защита",
118
+ fen: "rnbqkb1r/ppp2ppp/3p1n2/4p3/2PP4/2N5/PP2PPPP/R1BQKBNR w KQkq - 0 4",
119
+ },
120
+ {
121
+ id: "kings-gambit",
122
+ label: "Королевский гамбит",
123
+ fen: "rnbqkbnr/pppp1p1p/8/6p1/4Pp2/5N2/PPPP2PP/RNBQKB1R w KQkq - 0 4",
124
+ },
125
+ {
126
+ id: "petrov-defense",
127
+ label: "Защита Петрова",
128
+ fen: "rnbqkb1r/ppp2ppp/3p4/8/4n3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 0 5",
129
+ },
130
+ {
131
+ id: "vienna-game",
132
+ label: "Венская партия",
133
+ fen: "rnbqkb1r/pppp1ppp/5n2/4p3/4PP2/2N5/PPPP2PP/R1BQKBNR b KQkq - 0 3",
134
+ },
135
+ {
136
+ id: "pirc-defense",
137
+ label: "Защита Пирца",
138
+ fen: "rnbqkb1r/ppp1pp1p/3p1np1/8/3PP3/2N5/PPP2PPP/R1BQKBNR w KQkq - 0 4",
139
+ },
140
+ {
141
+ id: "scotch-gambit",
142
+ label: "Шотландский гамбит",
143
+ fen: "r1bqkbnr/pppp1ppp/2n5/8/2BpP3/5N2/PPP2PPP/RNBQK2R b KQkq - 1 4",
144
+ },
145
+ {
146
+ id: "two-knights-defense",
147
+ label: "Защита двух коней",
148
+ fen: "r1bqkb1r/pppp1ppp/2n2n2/4p3/2B1P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 4 4",
149
+ },
150
+ {
151
+ id: "dutch-defense",
152
+ label: "Голландская защита",
153
+ fen: "rnbq1rk1/ppppb1pp/4pn2/5p2/2PP4/5NP1/PP2PPBP/RNBQK2R w KQ - 4 6",
154
+ },
155
+ {
156
+ id: "benoni-defense",
157
+ label: "Защита Бенони",
158
+ fen: "rnbqkb1r/pp3ppp/3p1n2/2pP4/8/2N5/PP2PPPP/R1BQKBNR w KQkq - 0 6",
159
+ },
160
+ {
161
+ id: "catalan-opening",
162
+ label: "Каталонское начало",
163
+ fen: "rnbq1rk1/ppp1bppp/4pn2/3p4/2PP4/5NP1/PP2PPBP/RNBQK2R w KQ - 4 6",
164
+ },
165
+ {
166
+ id: "budapest-gambit",
167
+ label: "Будапештский гамбит",
168
+ fen: "rnbqkb1r/pppp1ppp/8/4P3/2P3n1/8/PP2PPPP/RNBQKBNR w KQkq - 1 4",
169
+ },
170
+ {
171
+ id: "colle-system",
172
+ label: "Система Колле",
173
+ fen: "rnbqkb1r/pp3ppp/4pn2/2pp4/3P4/2PBPN2/PP3PPP/RNBQK2R b KQkq - 0 5",
174
+ },
175
+ {
176
+ id: "reti-opening",
177
+ label: "Начало Рети",
178
+ fen: "rnbqkbnr/ppp1pppp/8/8/1PPp4/5N2/P2PPPPP/RNBQKB1R b KQkq - 0 3",
179
+ },
180
+ {
181
+ id: "center-game",
182
+ label: "Центральный дебют",
183
+ fen: "r1bqkbnr/pppp1ppp/2n5/8/3QP3/8/PPP2PPP/RNB1KBNR w KQkq - 1 4",
184
+ },
185
+ {
186
+ id: "queens-indian-defense",
187
+ label: "Ферзевоиндийская защита",
188
+ fen: "rnbqkb1r/p1pp1ppp/1p2pn2/8/2PP4/5N2/PP2PPPP/RNBQKB1R w KQkq - 0 4",
189
+ },
190
+ {
191
+ id: "benko-gambit",
192
+ label: "Гамбит Волга-Бодянского",
193
+ fen: "rnbqkb1r/p2ppppp/5n2/1ppP4/2P5/8/PP2PPPP/RNBQKBNR w KQkq - 0 4",
194
+ },
195
+ {
196
+ id: "tarrasch-defense",
197
+ label: "Защита Тарраша",
198
+ fen: "rnbqkbnr/pp3ppp/8/2pp4/3P4/2N5/PP2PPPP/R1BQKBNR w KQkq - 0 5",
199
+ },
200
+ {
201
+ id: "english-symmetrical",
202
+ label: "Английская: симметричная",
203
+ fen: "r1bqk1nr/pp1pppbp/2n3p1/2p5/2P5/2N3P1/PP1PPPBP/R1BQK1NR w KQkq - 2 5",
204
+ },
205
+ {
206
+ id: "evans-gambit",
207
+ label: "Гамбит Эванса",
208
+ fen: "r1bqk1nr/pppp1ppp/2n5/2b1p3/1PB1P3/5N2/P1PP1PPP/RNBQK2R b KQkq - 0 4",
209
+ },
210
+ {
211
+ id: "four-knights-game",
212
+ label: "Партия четырёх коней",
213
+ fen: "r1bqkb1r/pppp1ppp/2n2n2/4p3/4P3/2N2N2/PPPP1PPP/R1BQKB1R w KQkq - 4 4",
214
+ },
215
+ {
216
+ id: "modern-defense",
217
+ label: "Современная защита",
218
+ fen: "rnbqk1nr/ppp1ppbp/3p2p1/8/3PP3/2N5/PPP2PPP/R1BQKBNR w KQkq - 0 4",
219
+ },
220
+ {
221
+ id: "east-indian-defense",
222
+ label: "Остиндийская защита",
223
+ fen: "rnbq1rk1/ppp1ppbp/3p1np1/8/2PP4/5NP1/PP2PPBP/RNBQK2R w KQ - 0 6",
224
+ },
225
+ {
226
+ id: "owen-defense",
227
+ label: "Защита Оуэна",
228
+ fen: "rn1qkbnr/bp1ppppp/1p6/8/3PP3/5N2/PPP2PPP/RNBQKB1R b KQkq - 2 3",
229
+ },
230
+ {
231
+ id: "philidor-defense",
232
+ label: "Защита Филидора",
233
+ fen: "rnbqkb1r/ppp2ppp/3p1n2/8/3NP3/8/PPP2PPP/RNBQKB1R w KQkq - 1 5",
234
+ },
235
+ {
236
+ id: "scandinavian-modern",
237
+ label: "Скандинавская: современная",
238
+ fen: "rnbqkb1r/ppp1pppp/5n2/3P4/8/8/PPPP1PPP/RNBQKBNR w KQkq - 1 3",
239
+ },
240
+ {
241
+ id: "berlin-defense",
242
+ label: "Берлинская защита",
243
+ fen: "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 4 4",
244
+ },
245
+ {
246
+ id: "marshall-attack",
247
+ label: "Атака Маршалла",
248
+ fen: "r1bq1rk1/2p1bppp/p1n2n2/1p1pp3/4P3/1BP2N2/PP1P1PPP/RNBQR1K1 w - - 0 9",
249
+ },
250
+ {
251
+ id: "grob-opening",
252
+ label: "Начало Гроба",
253
+ fen: "rn1qkbnr/ppp1pppp/8/3p4/2P3b1/8/PP1PPPBP/RNBQK1NR b KQkq - 0 3",
254
+ },
255
+ {
256
+ id: "bird-opening",
257
+ label: "Начало Бёрда",
258
+ fen: "rnbqkb1r/ppp1pppp/5n2/3p4/5P2/4PN2/PPPP2PP/RNBQKB1R b KQkq - 0 3",
259
+ },
260
+ {
261
+ id: "larsen-opening",
262
+ label: "Начало Ларсена",
263
+ fen: "r1bqkbnr/pppp1ppp/2n5/4p3/8/1P2P3/PBPP1PPP/RN1QKBNR b KQkq - 0 3",
264
+ },
265
+ ];
266
+ /**
267
+ * Представляет каталог тактических приёмов для выбора до трёх тегов.
268
+ */
269
+ export const PUZZLE_TACTIC_TAGS = [
270
+ { id: "fork", label: "Двойной удар" },
271
+ { id: "pin", label: "Связка" },
272
+ { id: "skewer", label: "Рентген" },
273
+ { id: "zugzwang", label: "Цугцванг" },
274
+ { id: "deflection", label: "Отвлечение" },
275
+ { id: "decoy", label: "Завлечение" },
276
+ { id: "overloading", label: "Перегрузка" },
277
+ { id: "removal-of-defender", label: "Удаление защитника" },
278
+ { id: "blocking", label: "Блокирование" },
279
+ { id: "exchange-sacrifice", label: "Жертва качества" },
280
+ { id: "perpetual-check", label: "Вечный шах" },
281
+ { id: "stalemate", label: "Пат" },
282
+ { id: "trapped-piece", label: "Выигрыш материала" },
283
+ { id: "windmill", label: "Мельница" },
284
+ { id: "triangulation", label: "Триангуляция" },
285
+ { id: "intermezzo", label: "Промежуточный ход" },
286
+ { id: "quiet-move", label: "Тихий ход" },
287
+ { id: "counterattack", label: "Контратака" },
288
+ { id: "defensive-combination", label: "Защитная комбинация" },
289
+ { id: "opposition", label: "Оппозиция" },
290
+ ];
291
+ /** Возвращает максимальное число выбираемых тактических тегов. */
292
+ export const PUZZLE_TACTIC_TAGS_MAX = 3;
@@ -0,0 +1,117 @@
1
+ <script lang="ts" module>
2
+ export type { TWizardStepContext, TWizardStep } from "./wizardContext.js";
3
+ </script>
4
+
5
+ <script lang="ts" generics="S">
6
+ import type { Snippet } from "svelte";
7
+
8
+ import {
9
+ setWizardContext,
10
+ type TWizardStep,
11
+ type TWizardStepContext,
12
+ } from "./wizardContext.js";
13
+
14
+ interface Props {
15
+ /** Возвращает общий state визарда (двухсторонняя привязка). */
16
+ wizardState: S;
17
+ /** Возвращает описание шагов для индикатора прогресса. */
18
+ steps: readonly TWizardStep[];
19
+ /** Возвращает индекс начального шага (1-based). */
20
+ initialStep?: number;
21
+ /** Возвращает сигнал сброса: при изменении текущий шаг возвращается к `initialStep`. */
22
+ resetSignal?: unknown;
23
+ /** Возвращает колбэк завершения визарда с финальным state. */
24
+ onDone?: (state: S) => void;
25
+ /** Возвращает дополнительные классы корневого контейнера. */
26
+ class?: string;
27
+ /** Возвращает snippet содержимого шагов с контекстом визарда. */
28
+ children: Snippet<[TWizardStepContext<S>]>;
29
+ }
30
+
31
+ let {
32
+ wizardState = $bindable(),
33
+ steps,
34
+ initialStep = 1,
35
+ resetSignal,
36
+ onDone,
37
+ class: className,
38
+ children,
39
+ }: Props = $props();
40
+
41
+ let currentStep = $state(1);
42
+
43
+ $effect(() => {
44
+ void resetSignal;
45
+ currentStep = initialStep;
46
+ });
47
+
48
+ /**
49
+ * Представляет переход на следующий шаг (no-op на последнем).
50
+ */
51
+ function next() {
52
+ if (currentStep < steps.length) currentStep += 1;
53
+ }
54
+
55
+ /**
56
+ * Представляет переход на предыдущий шаг (no-op на первом).
57
+ */
58
+ function back() {
59
+ if (currentStep > 1) currentStep -= 1;
60
+ }
61
+
62
+ /**
63
+ * Представляет переход на произвольный шаг по индексу (1-based).
64
+ */
65
+ function goto(step: number) {
66
+ if (step >= 1 && step <= steps.length) currentStep = step;
67
+ }
68
+
69
+ /**
70
+ * Представляет завершение визарда с вызовом `onDone`.
71
+ */
72
+ function done() {
73
+ onDone?.(wizardState);
74
+ }
75
+
76
+ const wizard: TWizardStepContext<S> = {
77
+ get state() {
78
+ return wizardState;
79
+ },
80
+ get currentStep() {
81
+ return currentStep;
82
+ },
83
+ get totalSteps() {
84
+ return steps.length;
85
+ },
86
+ next,
87
+ back,
88
+ goto,
89
+ done,
90
+ };
91
+
92
+ setWizardContext(wizard);
93
+ </script>
94
+
95
+ <div class={className ?? "mx-4 lg:container lg:mx-auto"}>
96
+ <!-- ponytail: pb-px — запас под active:translate-y-px у кнопок «Далее»/«Готово» в overflow-контейнере диалога -->
97
+ <div class="flex flex-col gap-4 pt-4 pb-px">
98
+ <div class="flex items-center gap-2">
99
+ {#each steps as step, index (step.id)}
100
+ {#if index > 0}
101
+ <span class="h-px flex-1 bg-border"></span>
102
+ {/if}
103
+ <span
104
+ class="flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium"
105
+ class:bg-primary={currentStep >= index + 1}
106
+ class:bg-muted={currentStep < index + 1}
107
+ class:text-primary-foreground={currentStep >= index + 1}
108
+ >
109
+ {index + 1}
110
+ </span>
111
+ <span class="text-sm">{step.title}</span>
112
+ {/each}
113
+ </div>
114
+
115
+ {@render children(wizard)}
116
+ </div>
117
+ </div>
@@ -0,0 +1,42 @@
1
+ export type { TWizardStepContext, TWizardStep } from "./wizardContext.js";
2
+ import type { Snippet } from "svelte";
3
+ import { type TWizardStep, type TWizardStepContext } from "./wizardContext.js";
4
+ declare function $$render<S>(): {
5
+ props: {
6
+ /** Возвращает общий state визарда (двухсторонняя привязка). */
7
+ wizardState: S;
8
+ /** Возвращает описание шагов для индикатора прогресса. */
9
+ steps: readonly TWizardStep[];
10
+ /** Возвращает индекс начального шага (1-based). */
11
+ initialStep?: number;
12
+ /** Возвращает сигнал сброса: при изменении текущий шаг возвращается к `initialStep`. */
13
+ resetSignal?: unknown;
14
+ /** Возвращает колбэк завершения визарда с финальным state. */
15
+ onDone?: (state: S) => void;
16
+ /** Возвращает дополнительные классы корневого контейнера. */
17
+ class?: string;
18
+ /** Возвращает snippet содержимого шагов с контекстом визарда. */
19
+ children: Snippet<[TWizardStepContext<S>]>;
20
+ };
21
+ exports: {};
22
+ bindings: "wizardState";
23
+ slots: {};
24
+ events: {};
25
+ };
26
+ declare class __sveltets_Render<S> {
27
+ props(): ReturnType<typeof $$render<S>>['props'];
28
+ events(): ReturnType<typeof $$render<S>>['events'];
29
+ slots(): ReturnType<typeof $$render<S>>['slots'];
30
+ bindings(): "wizardState";
31
+ exports(): {};
32
+ }
33
+ interface $$IsomorphicComponent {
34
+ new <S>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<S>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<S>['props']>, ReturnType<__sveltets_Render<S>['events']>, ReturnType<__sveltets_Render<S>['slots']>> & {
35
+ $$bindings?: ReturnType<__sveltets_Render<S>['bindings']>;
36
+ } & ReturnType<__sveltets_Render<S>['exports']>;
37
+ <S>(internal: unknown, props: ReturnType<__sveltets_Render<S>['props']> & {}): ReturnType<__sveltets_Render<S>['exports']>;
38
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
39
+ }
40
+ declare const Wizard: $$IsomorphicComponent;
41
+ type Wizard<S> = InstanceType<typeof Wizard<S>>;
42
+ export default Wizard;
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import { onMount } from "svelte";
3
+
4
+ import { getWizardContext } from "./wizardContext.js";
5
+ import type { TWizardStepContext } from "./wizardContext.js";
6
+
7
+ interface Props {
8
+ /** Возвращает колбэк с захваченным контекстом визарда. */
9
+ onCapture: (ctx: TWizardStepContext<{ n: number }>) => void;
10
+ }
11
+
12
+ const { onCapture }: Props = $props();
13
+
14
+ onMount(() => {
15
+ onCapture(getWizardContext());
16
+ });
17
+ </script>
@@ -0,0 +1,10 @@
1
+ import type { TWizardStepContext } from "./wizardContext.js";
2
+ interface Props {
3
+ /** Возвращает колбэк с захваченным контекстом визарда. */
4
+ onCapture: (ctx: TWizardStepContext<{
5
+ n: number;
6
+ }>) => void;
7
+ }
8
+ declare const WizardContextConsumer: import("svelte").Component<Props, {}, "">;
9
+ type WizardContextConsumer = ReturnType<typeof WizardContextConsumer>;
10
+ export default WizardContextConsumer;
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import WizardContextConsumer from "./WizardContextConsumer.svelte";
3
+ import { setWizardContext, type TWizardStepContext } from "./wizardContext.js";
4
+
5
+ interface Props {
6
+ /** Возвращает колбэк с захваченным контекстом визарда. */
7
+ onCapture: (ctx: TWizardStepContext<{ n: number }>) => void;
8
+ }
9
+
10
+ const { onCapture }: Props = $props();
11
+
12
+ const ctx: TWizardStepContext<{ n: number }> = {
13
+ get state() {
14
+ return { n: 42 };
15
+ },
16
+ get currentStep() {
17
+ return 2;
18
+ },
19
+ get totalSteps() {
20
+ return 3;
21
+ },
22
+ next: () => {},
23
+ back: () => {},
24
+ goto: () => {},
25
+ done: () => {},
26
+ };
27
+
28
+ setWizardContext(ctx);
29
+ </script>
30
+
31
+ <WizardContextConsumer {onCapture} />
@@ -0,0 +1,10 @@
1
+ import { type TWizardStepContext } from "./wizardContext.js";
2
+ interface Props {
3
+ /** Возвращает колбэк с захваченным контекстом визарда. */
4
+ onCapture: (ctx: TWizardStepContext<{
5
+ n: number;
6
+ }>) => void;
7
+ }
8
+ declare const WizardContextProvider: import("svelte").Component<Props, {}, "">;
9
+ type WizardContextProvider = ReturnType<typeof WizardContextProvider>;
10
+ export default WizardContextProvider;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Представляет контекст визарда, доступный шагам через `getWizardContext` или snippet-параметр.
3
+ */
4
+ export type TWizardStepContext<S> = {
5
+ /** Возвращает общий state визарда (генерик по типу). */
6
+ readonly state: S;
7
+ /** Возвращает индекс текущего шага (1-based). */
8
+ readonly currentStep: number;
9
+ /** Возвращает общее число шагов. */
10
+ readonly totalSteps: number;
11
+ /** Представляет переход на следующий шаг (no-op на последнем). */
12
+ next: () => void;
13
+ /** Представляет переход на предыдущий шаг (no-op на первом). */
14
+ back: () => void;
15
+ /** Представляет переход на произвольный шаг по индексу (1-based). */
16
+ goto: (step: number) => void;
17
+ /** Представляет завершение визарда — вызывает `onDone` родителя с финальным state. */
18
+ done: () => void;
19
+ };
20
+ /**
21
+ * Представляет описание одного шага визарда для индикатора прогресса.
22
+ */
23
+ export interface TWizardStep {
24
+ /** Возвращает уникальный идентификатор шага. */
25
+ id: string;
26
+ /** Возвращает подпись шага в индикаторе прогресса. */
27
+ title: string;
28
+ }
29
+ /**
30
+ * Представляет регистрацию контекста визарда для потомков.
31
+ */
32
+ export declare function setWizardContext<S>(ctx: TWizardStepContext<S>): void;
33
+ /**
34
+ * Представляет чтение контекста визарда из шага-потомка.
35
+ */
36
+ export declare function getWizardContext<S>(): TWizardStepContext<S>;
@@ -0,0 +1,14 @@
1
+ import { getContext, setContext } from "svelte";
2
+ const WIZARD_KEY = Symbol("wizard");
3
+ /**
4
+ * Представляет регистрацию контекста визарда для потомков.
5
+ */
6
+ export function setWizardContext(ctx) {
7
+ setContext(WIZARD_KEY, ctx);
8
+ }
9
+ /**
10
+ * Представляет чтение контекста визарда из шага-потомка.
11
+ */
12
+ export function getWizardContext() {
13
+ return getContext(WIZARD_KEY);
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@connectorvol/shared",
3
- "version": "8.0.1",
3
+ "version": "9.0.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",
@@ -42,23 +42,25 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@ianvs/prettier-plugin-sort-imports": "4.5.1",
45
- "@internationalized/date": "^3.12.0",
46
- "@lucide/svelte": "^1.16.0",
45
+ "@internationalized/date": "3.12.2",
46
+ "@lucide/svelte": "1.21.0",
47
47
  "@playwright/test": "1.54.1",
48
48
  "@sveltejs/adapter-static": "3.0.10",
49
- "@sveltejs/kit": "2.48.0",
49
+ "@sveltejs/kit": "2.49.1",
50
50
  "@sveltejs/package": "2.4.0",
51
51
  "@sveltejs/vite-plugin-svelte": "7.0.0",
52
+ "@testing-library/svelte": "5.3.1",
52
53
  "@tailwindcss/forms": "0.5.10",
53
54
  "@tailwindcss/postcss": "4.1.11",
54
55
  "@tailwindcss/typography": "0.5.16",
55
56
  "@tailwindcss/vite": "4.1.11",
56
57
  "autoprefixer": "10.4.21",
57
- "svelte-check": "4.3.2",
58
+ "svelte-check": "4.6.0",
58
59
  "tailwind-merge": "3.3.1",
59
- "tailwind-variants": "^3.2.2",
60
+ "tailwind-variants": "3.2.2",
60
61
  "tailwindcss": "4.1.11",
61
62
  "tw-animate-css": "1.4.0",
63
+ "jsdom": "25.0.1",
62
64
  "typescript": "6.0.2",
63
65
  "vite": "8.0.7",
64
66
  "vite-plugin-checker": "0.12.0",
@@ -66,6 +68,6 @@
66
68
  "vitest": "4.0.17"
67
69
  },
68
70
  "peerDependencies": {
69
- "svelte": "^5.53.12"
71
+ "svelte": "5.56.3"
70
72
  }
71
73
  }