@connectorvol/chess-widgets 1.0.0 → 1.1.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.
@@ -1,53 +1,21 @@
1
1
  <script lang="ts">
2
- import type {
3
- ChessboardTheme,
4
- IChessBoardActions,
5
- } from "@connectorvol/chessboard";
6
- import type { Square } from "@connectorvol/shared";
2
+ import type { ChessboardTheme } from "@connectorvol/chessboard";
7
3
 
8
- import {
9
- Chessboard,
10
- CHESSBOARD_THEMES,
11
- createBoardApi,
12
- DEFAULT_BOARD_SETTINGS,
13
- Draggable,
14
- } from "@connectorvol/chessboard";
15
- import {
16
- ChessTree,
17
- TreeViewer,
18
- transformPgnToChessNode,
19
- } from "@connectorvol/tree";
20
4
  import { Popover } from "bits-ui";
21
5
  import { buttonVariants } from "../button-variants.js";
22
6
  import { cn } from "../utils.js";
23
7
 
24
- import { untrack } from "svelte";
25
- import { INITIAL_FEN } from "@connectorvol/chessops/fen";
26
- import { PgnOps } from "@connectorvol/chessops/pgnOps.svelte";
27
- import { Color, DEFAULT_PIECE_SET, type Move } from "@connectorvol/shared";
8
+ import { Color } from "@connectorvol/shared";
28
9
 
29
- import {
30
- createEmptyTreeFromFen,
31
- type PuzzleData,
32
- } from "../puzzle/puzzleData.js";
33
- import {
34
- puzzlePreviewClassifySolverMove,
35
- puzzlePreviewDupSubtreeUnderStudentCursor,
36
- puzzlePreviewIsSolvedPosition,
37
- puzzlePreviewSideToMoveFromFen,
38
- puzzlePreviewNodeAtPath,
39
- type TSolverMoveOutcome,
40
- } from "../puzzle/puzzleStepPreviewSolver.js";
10
+ import type { PuzzleData } from "../puzzle/puzzleData.js";
41
11
  import {
42
12
  puzzlePartsFromFullPgn,
43
13
  type TPuzzleCreatedPayload,
44
14
  } from "../puzzle/puzzleCreatedPayload.js";
15
+ import { PREVIEW_WRONG_NO_VARIANT_MESSAGE } from "../puzzle/puzzlePreviewConstants.js";
16
+ import PuzzlePgnBoardTreeEditor from "./PuzzlePgnBoardTreeEditor.svelte";
45
17
  import type { TChessboardAppearanceSettings } from "./types.js";
46
18
 
47
- /** Сообщение «нет такого продолжения» показывается только через кнопку «!» в шапке (как на шаге 2). */
48
- const PREVIEW_WRONG_NO_VARIANT_MESSAGE =
49
- "Такого продолжения нет среди вариантов задачи.";
50
-
51
19
  interface Props {
52
20
  /** Возвращает данные задачи (стартовый FEN и главная линия SAN для совместимости). */
53
21
  puzzleData: PuzzleData;
@@ -73,366 +41,8 @@
73
41
  : Color.WHITE,
74
42
  );
75
43
 
76
- let cursorPath = $state<number[]>([]);
77
- let solved = $state(false);
78
44
  let wrongFeedback = $state<string | null>(null);
79
-
80
- /** Высота блока с шахматной доской (px), чтобы выровнять высоту TreeViewer по доске на lg. */
81
- let chessboardBlockHeight = $state(0);
82
-
83
- let wrongRevealTimer: ReturnType<typeof setTimeout> | null = null;
84
- let advanceLineTimer: ReturnType<typeof setTimeout> | null = null;
85
-
86
- let previewChess = new PgnOps(INITIAL_FEN, "chess");
87
-
88
- const studentPreviewTree = new ChessTree(createEmptyTreeFromFen(INITIAL_FEN));
89
-
90
- let solutionPreviewTree = $state<ChessTree | null>(null);
91
-
92
- /**
93
- * Представляет синхронизацию доступности перетаскивания фигур с очередью хода и состоянием «решено».
94
- */
95
- function syncBoardDragFromChessTurn(): void {
96
- chessboard.draggable = solved
97
- ? Draggable.NONE
98
- : previewChess.turn() === solverColor
99
- ? solverColor === Color.WHITE
100
- ? Draggable.WHITE
101
- : Draggable.BLACK
102
- : Draggable.NONE;
103
- }
104
-
105
- /**
106
- * Представляет добавление (если отсутствует) пути в TreeViewer ученика без очистки уже пройденных линий.
107
- */
108
- function ensureStudentPreviewTreeHasPath(path: number[]): void {
109
- const solution = solutionPreviewTree;
110
- if (!solution) return;
111
-
112
- studentPreviewTree.currentNode = studentPreviewTree.rootNode.moves;
113
-
114
- let src = solution.rootNode.moves;
115
- for (const idx of path) {
116
- const next = src.children[idx];
117
- studentPreviewTree.addNodeToCurrent({
118
- id: "",
119
- children: [],
120
- data: { ...next.data },
121
- });
122
- src = next;
123
- }
124
- }
125
-
126
- /**
127
- * Представляет обработку ошибочного хода с показом неверной ветки или сообщения без варианта.
128
- */
129
- function handleWrongOutcome(outcome: TSolverMoveOutcome): void {
130
- const solution = solutionPreviewTree;
131
- if (!solution) return;
132
-
133
- if (wrongRevealTimer !== null) {
134
- clearTimeout(wrongRevealTimer);
135
- wrongRevealTimer = null;
136
- }
137
- if (advanceLineTimer !== null) {
138
- clearTimeout(advanceLineTimer);
139
- advanceLineTimer = null;
140
- }
141
-
142
- if (outcome.kind === "wrong_marked_variant") {
143
- wrongFeedback =
144
- "Неверно. Открываю введённый вариант в дереве, ход отменён.";
145
- // Ход на доске не применяется (мы возвращаем undefined), но в TreeViewer
146
- // добавляем ветку неверного ответа, чтобы её можно было изучить.
147
- ensureStudentPreviewTreeHasPath(cursorPath);
148
- puzzlePreviewDupSubtreeUnderStudentCursor(
149
- studentPreviewTree,
150
- outcome.wrongBranchRoot,
151
- );
152
- return;
153
- }
154
-
155
- wrongFeedback = PREVIEW_WRONG_NO_VARIANT_MESSAGE;
156
- }
157
-
158
- /**
159
- * Представляет установку позиции и дерева по пути из корня.
160
- */
161
- function setStateFromPath(path: number[]): void {
162
- const solution = solutionPreviewTree;
163
- if (!solution) return;
164
-
165
- previewChess.setFen(props.puzzleData.initialFen);
166
- let node = solution.rootNode.moves;
167
- for (const idx of path) {
168
- const child = node.children[idx]!;
169
- previewChess.makeSanMove(child.data.san);
170
- node = child;
171
- }
172
-
173
- cursorPath = path;
174
- ensureStudentPreviewTreeHasPath(cursorPath);
175
- chessboard.fen = previewChess.fen();
176
- syncBoardDragFromChessTurn();
177
- }
178
-
179
- /**
180
- * Представляет автоматический ход соперника по основной линии (первый вариант), если сейчас ход соперника.
181
- * Возвращает новый путь.
182
- */
183
- function applyOpponentMainLineMove(pathAfterSolver: number[]): number[] {
184
- const solution = solutionPreviewTree;
185
- if (!solution) return pathAfterSolver;
186
-
187
- if (puzzlePreviewSideToMoveFromFen(previewChess.fen()) === solverColor) {
188
- return pathAfterSolver;
189
- }
190
-
191
- const node = puzzlePreviewNodeAtPath(
192
- solution.rootNode.moves,
193
- pathAfterSolver,
194
- );
195
- if (node.children.length === 0) return pathAfterSolver;
196
-
197
- previewChess.makeSanMove(node.children[0]!.data.san);
198
- return [...pathAfterSolver, 0];
199
- }
200
-
201
- /**
202
- * Представляет поиск следующей линии по развилкам соперника (DFS: чем глубже развилка — тем раньше возврат).
203
- */
204
- function findNextOpponentLine(path: number[]): number[] | null {
205
- const solution = solutionPreviewTree;
206
- if (!solution) return null;
207
-
208
- let node = solution.rootNode.moves;
209
- for (let depth = 0; depth <= path.length; depth++) {
210
- // depth === path.length соответствует текущей позиции (узел node)
211
- const sideToMove = puzzlePreviewSideToMoveFromFen(node.data.fen);
212
- const isOpponentToMove = sideToMove !== solverColor;
213
- const isFork = node.children.length > 1;
214
-
215
- if (isOpponentToMove && isFork && depth < path.length) {
216
- const chosenIdx = path[depth]!;
217
- if (chosenIdx < node.children.length - 1) {
218
- // кандидат на "следующую линию" с этого форка
219
- // но продолжаем вниз, чтобы взять самый глубокий
220
- }
221
- }
222
-
223
- if (depth === path.length) break;
224
- node = node.children[path[depth]!]!;
225
- }
226
-
227
- // Второй проход: выбираем самый глубокий форк соперника, где есть непройденные ответы.
228
- node = solution.rootNode.moves;
229
- let bestForkDepth: number | null = null;
230
- let bestNextIdx = 0;
231
- for (let depth = 0; depth < path.length; depth++) {
232
- const sideToMove = puzzlePreviewSideToMoveFromFen(node.data.fen);
233
- const isOpponentToMove = sideToMove !== solverColor;
234
- if (isOpponentToMove && node.children.length > 1) {
235
- const chosenIdx = path[depth]!;
236
- if (chosenIdx < node.children.length - 1) {
237
- bestForkDepth = depth;
238
- bestNextIdx = chosenIdx + 1;
239
- }
240
- }
241
- node = node.children[path[depth]!]!;
242
- }
243
-
244
- if (bestForkDepth === null) return null;
245
- return [...path.slice(0, bestForkDepth), bestNextIdx];
246
- }
247
-
248
- /**
249
- * Представляет переход на следующую линию (следующий ответ соперника), если она есть.
250
- */
251
- function maybeAdvanceToNextOpponentLine(): boolean {
252
- const nextBase = findNextOpponentLine(cursorPath);
253
- if (!nextBase) return false;
254
-
255
- solved = false;
256
- wrongFeedback = null;
257
-
258
- // После выбора нового ответа соперника нужно довести позицию до актуальной точки:
259
- // ставим состояние на basePath (до хода соперника), затем делаем выбранный ход соперника (он уже в пути).
260
- setStateFromPath(nextBase);
261
- return true;
262
- }
263
-
264
- /**
265
- * Представляет попытку применить SAN хода решателя с автответами соперника по дереву.
266
- */
267
- function tryApplySolverSan(san: string): Move | undefined {
268
- const solution = solutionPreviewTree;
269
- if (!solution || solved) return undefined;
270
-
271
- const cursorNode = puzzlePreviewNodeAtPath(
272
- solution.rootNode.moves,
273
- cursorPath,
274
- );
275
-
276
- const outcome = puzzlePreviewClassifySolverMove(
277
- cursorNode,
278
- previewChess.fen(),
279
- san,
280
- solverColor,
281
- );
282
-
283
- if (outcome.kind !== "correct") {
284
- handleWrongOutcome(outcome);
285
- return undefined;
286
- }
287
-
288
- try {
289
- let path = [...cursorPath, outcome.childIndex];
290
- const moveRecord = previewChess.makeSanMove(san);
291
- path = applyOpponentMainLineMove(path);
292
- setStateFromPath(path);
293
-
294
- const leaf = puzzlePreviewNodeAtPath(solution.rootNode.moves, cursorPath);
295
- if (puzzlePreviewIsSolvedPosition(previewChess, leaf, solverColor)) {
296
- solved = true;
297
- if (advanceLineTimer !== null) {
298
- clearTimeout(advanceLineTimer);
299
- advanceLineTimer = null;
300
- }
301
- advanceLineTimer = setTimeout(() => {
302
- // Если есть ещё линии по развилкам соперника — переключаемся на следующую.
303
- if (maybeAdvanceToNextOpponentLine()) {
304
- // продолжаем в режиме решения
305
- }
306
- advanceLineTimer = null;
307
- }, 250);
308
- }
309
-
310
- wrongFeedback = null;
311
- syncBoardDragFromChessTurn();
312
-
313
- return moveRecord;
314
- } catch {
315
- wrongFeedback = "Ход недопустим в этой позиции.";
316
- return undefined;
317
- }
318
- }
319
-
320
- const actions: IChessBoardActions = {
321
- game: {
322
- possibleMovesOnSquare: (square: Square) => previewChess.moves(square),
323
- beforePieceMoveSan(san: string) {
324
- const move = tryApplySolverSan(san);
325
- if (!move) return undefined;
326
- return {
327
- move,
328
- fen: previewChess.fen(),
329
- turn: previewChess.turn(),
330
- };
331
- },
332
- afterPieceMoveSan: () => {
333
- syncBoardDragFromChessTurn();
334
- },
335
- beforePieceMove: (from, to, promotion) => {
336
- const san = previewChess.getSanForMove({ from, to, promotion });
337
- const move = tryApplySolverSan(san);
338
- if (!move) return "";
339
- return previewChess.fen();
340
- },
341
- afterPieceMove: () => {
342
- syncBoardDragFromChessTurn();
343
- },
344
- },
345
- };
346
-
347
- let chessboard = $derived(
348
- createBoardApi({
349
- fen: INITIAL_FEN,
350
- settings: {
351
- ...DEFAULT_BOARD_SETTINGS,
352
- ...(props.boardAppearanceSettings ?? {}),
353
- boardSize: 38,
354
- isResizable: false,
355
- orientation: Color.WHITE,
356
- draggable: Draggable.WHITE,
357
- },
358
- actions,
359
- theme: props.boardTheme ?? CHESSBOARD_THEMES.blue,
360
- }),
361
- );
362
-
363
- $effect(() => {
364
- const pgn = props.solutionPgn;
365
- const initialFen = props.puzzleData.initialFen;
366
- const orientation = solverColor;
367
-
368
- if (!pgn.trim()) {
369
- untrack(() => {
370
- solutionPreviewTree = null;
371
- previewChess.setFen(initialFen);
372
- studentPreviewTree.replaceRootTree(createEmptyTreeFromFen(initialFen));
373
- studentPreviewTree.currentNode = studentPreviewTree.rootNode.moves;
374
- chessboard.fen = initialFen;
375
- chessboard.orientation = orientation;
376
- syncBoardDragFromChessTurn();
377
- });
378
- return () => {
379
- if (wrongRevealTimer !== null) {
380
- clearTimeout(wrongRevealTimer);
381
- wrongRevealTimer = null;
382
- }
383
- if (advanceLineTimer !== null) {
384
- clearTimeout(advanceLineTimer);
385
- advanceLineTimer = null;
386
- }
387
- };
388
- }
389
-
390
- untrack(() => {
391
- const { rootNode } = transformPgnToChessNode(pgn);
392
- solutionPreviewTree = new ChessTree(rootNode);
393
-
394
- cursorPath = [];
395
- solved = false;
396
- wrongFeedback = null;
397
- previewChess.setFen(initialFen);
398
- studentPreviewTree.replaceRootTree(createEmptyTreeFromFen(initialFen));
399
- studentPreviewTree.currentNode = studentPreviewTree.rootNode.moves;
400
- chessboard.fen = initialFen;
401
- chessboard.orientation = orientation;
402
- syncBoardDragFromChessTurn();
403
- });
404
-
405
- return () => {
406
- if (wrongRevealTimer !== null) {
407
- clearTimeout(wrongRevealTimer);
408
- wrongRevealTimer = null;
409
- }
410
- if (advanceLineTimer !== null) {
411
- clearTimeout(advanceLineTimer);
412
- advanceLineTimer = null;
413
- }
414
- };
415
- });
416
-
417
- /**
418
- * Представляет заглушку синхронизации движка при выборе узла в дереве превью (доска решается отдельно).
419
- */
420
- function noopChessFen(_fen: string): void {}
421
-
422
- /**
423
- * Представляет заглушку обновления доски TreeViewer на шаге превью.
424
- */
425
- function noopChessboardFen(_animationTime?: number): void {}
426
-
427
- /**
428
- * Представляет пустые колбэки навигации TreeViewer без побочных эффектов.
429
- */
430
- function noopOnSelectNode(): void {}
431
-
432
- /**
433
- * Представляет пустой колбэк после удаления варианта в TreeViewer.
434
- */
435
- function noopOnDeleteVariant(): void {}
45
+ let solved = $state(false);
436
46
  </script>
437
47
 
438
48
  <div class="flex flex-col gap-3 pt-2 pb-0">
@@ -523,48 +133,14 @@
523
133
  {/if}
524
134
  </div>
525
135
 
526
- <div
527
- class="flex min-h-0 flex-col justify-center gap-4 lg:flex-row lg:items-start lg:gap-4"
528
- >
529
- <div class="flex w-full max-w-[38rem] shrink-0 flex-col gap-2">
530
- <div class="w-full shrink-0" bind:clientHeight={chessboardBlockHeight}>
531
- <Chessboard facade={chessboard} />
532
- </div>
533
- {#if wrongFeedback && wrongFeedback !== PREVIEW_WRONG_NO_VARIANT_MESSAGE}
534
- <p class="text-sm font-medium text-amber-600 dark:text-amber-400">
535
- {wrongFeedback}
536
- </p>
537
- {/if}
538
- </div>
539
-
540
- <div class="flex min-h-0 w-full flex-1 flex-col gap-2 lg:min-w-0">
541
- <div
542
- class={cn(
543
- "flex min-w-0 flex-col overflow-hidden rounded-md border border-border",
544
- chessboardBlockHeight > 0
545
- ? "min-h-0 shrink-0"
546
- : "min-h-[12rem] max-h-[min(65vh,36rem)]",
547
- )}
548
- style:height={chessboardBlockHeight > 0
549
- ? `${chessboardBlockHeight}px`
550
- : undefined}
551
- >
552
- <TreeViewer
553
- chessTree={solved && solutionPreviewTree
554
- ? solutionPreviewTree
555
- : studentPreviewTree}
556
- onSelectNode={noopOnSelectNode}
557
- onDeleteVariant={noopOnDeleteVariant}
558
- setChessFen={noopChessFen}
559
- setChessboardFen={noopChessboardFen}
560
- pieceSet={DEFAULT_PIECE_SET}
561
- className="min-h-0 flex-1 border-x-0 border-t-0"
562
- editMode={false}
563
- selectable={false}
564
- />
565
- </div>
566
- </div>
567
- </div>
136
+ <PuzzlePgnBoardTreeEditor
137
+ bind:wrongFeedback
138
+ bind:solved
139
+ pgn={props.solutionPgn}
140
+ fen={props.puzzleData.initialFen}
141
+ boardTheme={props.boardTheme}
142
+ boardAppearanceSettings={props.boardAppearanceSettings}
143
+ />
568
144
 
569
145
  <div class="flex justify-between gap-2">
570
146
  <button
@@ -1,5 +1,5 @@
1
1
  import type { ChessboardTheme } from "@connectorvol/chessboard";
2
- import { type PuzzleData } from "../puzzle/puzzleData.js";
2
+ import type { PuzzleData } from "../puzzle/puzzleData.js";
3
3
  import { type TPuzzleCreatedPayload } from "../puzzle/puzzleCreatedPayload.js";
4
4
  import type { TChessboardAppearanceSettings } from "./types.js";
5
5
  interface Props {
@@ -0,0 +1,16 @@
1
+ import type { ChessboardTheme } from "@connectorvol/chessboard";
2
+ import { type IChessBoardActions } from "@connectorvol/chessboard";
3
+ import { Color } from "@connectorvol/shared";
4
+ import type { TChessboardAppearanceSettings } from "./types.js";
5
+ /**
6
+ * Представляет определение стороны хода по полному FEN.
7
+ */
8
+ export declare function sideToMoveFromFullFen(fullFen: string): Color;
9
+ /**
10
+ * Представляет создание API доски для интерактивного построения линии (как в мастере задач):
11
+ * ориентация и перетаскивание по стороне хода, фиксированный размер доски.
12
+ */
13
+ export declare function createPuzzleLineEditingBoardApi(fullFen: string, actions: IChessBoardActions, opts?: {
14
+ boardTheme?: ChessboardTheme;
15
+ boardAppearanceSettings?: TChessboardAppearanceSettings;
16
+ }): import("@connectorvol/chessboard").BoardApi;
@@ -0,0 +1,31 @@
1
+ import { CHESSBOARD_THEMES, createBoardApi, DEFAULT_BOARD_SETTINGS, Draggable, } from "@connectorvol/chessboard";
2
+ import { Color } from "@connectorvol/shared";
3
+ import { DEFAULT_EDITABLE_BOARD_SETTINGS } from "../constants/editable-board-settings.js";
4
+ /**
5
+ * Представляет определение стороны хода по полному FEN.
6
+ */
7
+ export function sideToMoveFromFullFen(fullFen) {
8
+ const token = fullFen.trim().split(/\s+/)[1];
9
+ return token === "b" ? Color.BLACK : Color.WHITE;
10
+ }
11
+ /**
12
+ * Представляет создание API доски для интерактивного построения линии (как в мастере задач):
13
+ * ориентация и перетаскивание по стороне хода, фиксированный размер доски.
14
+ */
15
+ export function createPuzzleLineEditingBoardApi(fullFen, actions, opts = {}) {
16
+ const side = sideToMoveFromFullFen(fullFen);
17
+ const { boardSize: _boardSize, orientation: _orientation, draggable: _draggable, ...appearanceSettings } = (opts.boardAppearanceSettings ?? {});
18
+ return createBoardApi({
19
+ fen: fullFen,
20
+ settings: {
21
+ ...DEFAULT_BOARD_SETTINGS,
22
+ ...appearanceSettings,
23
+ boardSize: DEFAULT_EDITABLE_BOARD_SETTINGS.boardSize,
24
+ isResizable: false,
25
+ orientation: side,
26
+ draggable: side === Color.WHITE ? Draggable.WHITE : Draggable.BLACK,
27
+ },
28
+ actions,
29
+ theme: opts.boardTheme ?? CHESSBOARD_THEMES.blue,
30
+ });
31
+ }
@@ -4,6 +4,48 @@ import type { ChessBoardSettings, ChessboardTheme } from "@connectorvol/chessboa
4
4
  * Представляет тип визуальных настроек шахматной доски для мастера создания задачи.
5
5
  */
6
6
  export type TChessboardAppearanceSettings = Omit<Partial<ChessBoardSettings>, "boardSize" | "orientation" | "draggable">;
7
+ /**
8
+ * Представляет исход решения или ошибки в превью задачи для колбэка `onOutcome`.
9
+ */
10
+ export type TPuzzlePgnBoardTreeEditorOutcome = "solved" | "failed";
11
+ /**
12
+ * Представляет свойства компонента превью «до решения видно только пройденные ходы»:
13
+ * доска для решателя и TreeViewer без режима правки (как шаг 3 мастера создания задачи).
14
+ */
15
+ export interface TPuzzlePgnBoardTreeEditorProps {
16
+ /**
17
+ * Возвращает полный FEN стартовой позиции задачи (обязателен для согласованности с деревом; если не задан — начальная позиция классических шахмат).
18
+ */
19
+ fen?: string;
20
+ /**
21
+ * Возвращает текст партии: только ходы или полный PGN; заголовки внутри строки при сборке дерева игнорируются в пользу пропа `fen`.
22
+ */
23
+ pgn?: string;
24
+ /**
25
+ * Возвращает колбэк при ошибке хода (`failed`) или когда пройдены все обязательные линии превью по развилкам соперника (`solved`), как кнопка «Готово» на шаге 3 мастера.
26
+ */
27
+ onOutcome?: (result: TPuzzlePgnBoardTreeEditorOutcome) => void;
28
+ /**
29
+ * Возвращает текст ошибки превью для подписи под доской или индикатора «!» у родителя (двухсторонняя привязка).
30
+ */
31
+ wrongFeedback?: string | null;
32
+ /**
33
+ * Возвращает признак «все линии превью пройдены» — полное дерево решения на экране, как перед «Готово» в мастере (двухсторонняя привязка).
34
+ */
35
+ solved?: boolean;
36
+ /**
37
+ * Возвращает тему оформления шахматной доски (по умолчанию `CHESSBOARD_THEMES.blue`).
38
+ */
39
+ boardTheme?: ChessboardTheme;
40
+ /**
41
+ * Возвращает дополнительные визуальные настройки шахматной доски (кроме `boardSize`, `orientation`, `draggable`).
42
+ */
43
+ boardAppearanceSettings?: TChessboardAppearanceSettings;
44
+ /**
45
+ * Возвращает дополнительные классы Tailwind для корневого контейнера раскладки.
46
+ */
47
+ class?: string;
48
+ }
7
49
  /**
8
50
  * Представляет свойства компонента мастера создания шахматной задачи.
9
51
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@connectorvol/chess-widgets",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -40,10 +40,10 @@
40
40
  "test": ""
41
41
  },
42
42
  "dependencies": {
43
- "@connectorvol/chessboard": "2.2.0",
44
- "@connectorvol/chessops": "2.0.3",
45
- "@connectorvol/shared": "2.1.2",
46
- "@connectorvol/tree": "3.0.0",
43
+ "@connectorvol/chessboard": "4.0.0",
44
+ "@connectorvol/chessops": "3.0.0",
45
+ "@connectorvol/shared": "4.0.0",
46
+ "@connectorvol/tree": "4.0.0",
47
47
  "clsx": "^2.1.1",
48
48
  "tailwind-merge": "3.3.1",
49
49
  "tailwind-variants": "3.1.1"
@@ -51,6 +51,7 @@
51
51
  "devDependencies": {
52
52
  "@ianvs/prettier-plugin-sort-imports": "4.5.1",
53
53
  "@lucide/svelte": "^0.553.0",
54
+ "bits-ui": "2.16.4",
54
55
  "@sveltejs/adapter-static": "3.0.10",
55
56
  "@sveltejs/kit": "2.48.0",
56
57
  "@sveltejs/package": "2.4.0",