kokopu-react 2.0.1 → 3.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.
Files changed (136) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/lib/chessboard/Chessboard.d.ts +7 -2
  3. package/dist/lib/chessboard/Chessboard.js +43 -21
  4. package/dist/lib/chessboard/Chessboard.js.map +1 -1
  5. package/dist/lib/chessboard/ChessboardImpl.d.ts +2 -1
  6. package/dist/lib/chessboard/ChessboardImpl.js +9 -3
  7. package/dist/lib/chessboard/ChessboardImpl.js.map +1 -1
  8. package/dist/lib/chessboard/Draggable.d.ts +7 -1
  9. package/dist/lib/chessboard/Draggable.js +21 -29
  10. package/dist/lib/chessboard/Draggable.js.map +1 -1
  11. package/dist/lib/chessboard/colorsets.d.ts +4 -0
  12. package/dist/lib/chessboard/colorsets.js +4 -0
  13. package/dist/lib/chessboard/colorsets.js.map +1 -1
  14. package/dist/lib/chessboard/piecesets.d.ts +4 -0
  15. package/dist/lib/chessboard/piecesets.js +4 -0
  16. package/dist/lib/chessboard/piecesets.js.map +1 -1
  17. package/dist/lib/icons/ChessPieceIcon.d.ts +23 -0
  18. package/dist/lib/icons/ChessPieceIcon.js +65 -0
  19. package/dist/lib/icons/ChessPieceIcon.js.map +1 -0
  20. package/dist/lib/index.d.ts +2 -1
  21. package/dist/lib/index.js +2 -1
  22. package/dist/lib/index.js.map +1 -1
  23. package/dist/lib/movetext/Movetext.d.ts +3 -1
  24. package/dist/lib/movetext/Movetext.js.map +1 -1
  25. package/dist/lib/movetext/MovetextImpl.d.ts +3 -1
  26. package/dist/lib/movetext/MovetextImpl.js +15 -14
  27. package/dist/lib/movetext/MovetextImpl.js.map +1 -1
  28. package/dist/lib/sanitization.d.ts +1 -0
  29. package/dist/lib/sanitization.js +11 -0
  30. package/dist/lib/sanitization.js.map +1 -1
  31. package/dist/lib/types.d.ts +11 -1
  32. package/dist/lib/types.js +7 -1
  33. package/dist/lib/types.js.map +1 -1
  34. package/doc_src/demo/PageChessboardBase.tsx +7 -0
  35. package/doc_src/demo/PageChessboardSmallScreens.tsx +10 -3
  36. package/doc_src/demo/PageMovetextBase.tsx +8 -0
  37. package/doc_src/examples/ChessPieceIcon.md +3 -0
  38. package/doc_src/home.md +11 -0
  39. package/doc_src/migrate_to_3.md +51 -0
  40. package/package.json +16 -16
  41. package/scripts/doc.styleguide.config.js +6 -1
  42. package/scripts/docker-compose.yml +1 -1
  43. package/src/chessboard/Chessboard.tsx +56 -23
  44. package/src/chessboard/ChessboardImpl.tsx +10 -3
  45. package/src/chessboard/Draggable.tsx +22 -41
  46. package/src/chessboard/colorsets.ts +6 -0
  47. package/src/chessboard/piecesets.ts +6 -0
  48. package/src/icons/ChessPieceIcon.tsx +99 -0
  49. package/src/index.ts +4 -2
  50. package/src/movetext/Movetext.tsx +3 -1
  51. package/src/movetext/MovetextImpl.tsx +18 -14
  52. package/src/sanitization.ts +13 -0
  53. package/src/types.ts +17 -1
  54. package/test/02_chessboard_util.js +104 -36
  55. package/test/{04_marker_icons_graphic.js → 04_icons_graphic.js} +14 -2
  56. package/test/09_chessboard_small_screens.js +50 -0
  57. package/test/{09_movetext_graphic.js → 10_movetext_graphic.js} +5 -4
  58. package/test/{10_movetext_interaction.js → 11_movetext_interaction.js} +38 -14
  59. package/test/common/graphic.js +9 -0
  60. package/test/graphic_references/04_icons_graphic/chess_piece/customized_pieceset.png +0 -0
  61. package/test/graphic_references/04_icons_graphic/chess_piece/multiple_pieces.png +0 -0
  62. package/test/graphic_references/04_icons_graphic/chess_piece/single_piece.png +0 -0
  63. package/test/graphic_references/04_icons_graphic/marker/invalid_arrow_size.png +0 -0
  64. package/test/graphic_references/04_icons_graphic/marker/invalid_square_size.png +0 -0
  65. package/test/graphic_references/04_icons_graphic/marker/invalid_symbol.png +0 -0
  66. package/test/graphic_references/04_icons_graphic/marker/invalid_text_size.png +0 -0
  67. package/test/graphic_references/05_chessboard_graphic/base/from_fen.png +0 -0
  68. package/test/graphic_references/05_chessboard_graphic/flipped/default.png +0 -0
  69. package/test/graphic_references/06_chessboard_animation/base_1/capture.png +0 -0
  70. package/test/graphic_references/06_chessboard_animation/base_1/promotion.png +0 -0
  71. package/test/graphic_references/06_chessboard_animation/base_2/capture.png +0 -0
  72. package/test/graphic_references/06_chessboard_animation/base_2/promotion.png +0 -0
  73. package/test/graphic_references/06_chessboard_animation/base_3/capture.png +0 -0
  74. package/test/graphic_references/06_chessboard_animation/base_3/promotion.png +0 -0
  75. package/test/graphic_references/09_chessboard_small_screens/base/default.png +0 -0
  76. package/test/graphic_references/09_chessboard_small_screens/base/invalid_limits.png +0 -0
  77. package/test/graphic_references/09_chessboard_small_screens/base/width_690.png +0 -0
  78. package/test/graphic_references/09_chessboard_small_screens/base/width_700.png +0 -0
  79. package/test/graphic_references/09_chessboard_small_screens/base/width_710.png +0 -0
  80. package/test/graphic_references/09_chessboard_small_screens/base/width_720.png +0 -0
  81. package/test/graphic_references/09_chessboard_small_screens/base/width_730.png +0 -0
  82. package/test/graphic_references/09_chessboard_small_screens/base/width_740.png +0 -0
  83. package/test/graphic_references/09_chessboard_small_screens/base/width_750.png +0 -0
  84. package/test/graphic_references/10_movetext_graphic/options/other_diagram_options.png +0 -0
  85. package/test/graphic_test_app/04_icons_graphic/chess_piece.tsx +38 -0
  86. package/test/graphic_test_app/05_chessboard_graphic/base.tsx +2 -2
  87. package/test/graphic_test_app/05_chessboard_graphic/flipped.tsx +2 -2
  88. package/test/graphic_test_app/06_chessboard_animation/base_1.tsx +2 -2
  89. package/test/graphic_test_app/06_chessboard_animation/base_2.tsx +2 -2
  90. package/test/graphic_test_app/06_chessboard_animation/base_3.tsx +2 -2
  91. package/test/graphic_test_app/09_chessboard_small_screens/base.tsx +41 -0
  92. package/test/graphic_test_app/{09_movetext_graphic → 10_movetext_graphic}/options.tsx +1 -0
  93. /package/test/graphic_references/{04_marker_icons_graphic/base/invalid_symbol.png → 04_icons_graphic/chess_piece/invalid_multiple_pieces.png} +0 -0
  94. /package/test/graphic_references/{04_marker_icons_graphic/base/invalid_arrow_size.png → 04_icons_graphic/chess_piece/invalid_pieceset.png} +0 -0
  95. /package/test/graphic_references/{04_marker_icons_graphic/base/invalid_text_size.png → 04_icons_graphic/chess_piece/invalid_single_piece.png} +0 -0
  96. /package/test/graphic_references/{04_marker_icons_graphic/base/invalid_square_size.png → 04_icons_graphic/chess_piece/invalid_size.png} +0 -0
  97. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/colorized_arrow.png +0 -0
  98. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/colorized_square.png +0 -0
  99. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/colorized_symbol.png +0 -0
  100. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/colorized_text.png +0 -0
  101. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/default_arrow.png +0 -0
  102. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/default_square.png +0 -0
  103. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/default_text.png +0 -0
  104. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/wrapped_arrow.png +0 -0
  105. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/wrapped_square.png +0 -0
  106. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/wrapped_symbol.png +0 -0
  107. /package/test/graphic_references/{04_marker_icons_graphic/base → 04_icons_graphic/marker}/wrapped_text.png +0 -0
  108. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/base/game_1.png +0 -0
  109. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/base/game_2.png +0 -0
  110. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/base/game_3.png +0 -0
  111. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/base/game_4.png +0 -0
  112. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/error/pgn_parsing_error_1.png +0 -0
  113. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/error/pgn_parsing_error_2.png +0 -0
  114. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/error/wrong_game_index_1.png +0 -0
  115. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/error/wrong_game_index_2.png +0 -0
  116. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/error/wrong_game_index_type.png +0 -0
  117. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/error/wrong_game_type.png +0 -0
  118. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/html/filtered_tags_and_attributes.png +0 -0
  119. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/html/html_in_comments.png +0 -0
  120. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/html/html_in_headers.png +0 -0
  121. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/options/custom_piece_symbols.png +0 -0
  122. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/options/figurine_piece_symbols_and_diagram_options.png +0 -0
  123. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/options/hidden_diagrams.png +0 -0
  124. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/options/localized_piece_symbols.png +0 -0
  125. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/options/wrong_diagram_options_1.png +0 -0
  126. /package/test/graphic_references/{09_movetext_graphic → 10_movetext_graphic}/options/wrong_diagram_options_2.png +0 -0
  127. /package/test/graphic_references/{10_movetext_interaction → 11_movetext_interaction}/error/wrong_interaction_mode.png +0 -0
  128. /package/test/graphic_references/{10_movetext_interaction → 11_movetext_interaction}/select_moves/click_on_disabled.png +0 -0
  129. /package/test/graphic_references/{10_movetext_interaction → 11_movetext_interaction}/select_moves/click_on_unselected.png +0 -0
  130. /package/test/graphic_references/{10_movetext_interaction → 11_movetext_interaction}/select_moves/click_on_with_variations.png +0 -0
  131. /package/test/graphic_test_app/{04_marker_icons_graphic/base.tsx → 04_icons_graphic/marker.tsx} +0 -0
  132. /package/test/graphic_test_app/{09_movetext_graphic → 10_movetext_graphic}/base.tsx +0 -0
  133. /package/test/graphic_test_app/{09_movetext_graphic → 10_movetext_graphic}/error.tsx +0 -0
  134. /package/test/graphic_test_app/{09_movetext_graphic → 10_movetext_graphic}/html.tsx +0 -0
  135. /package/test/graphic_test_app/{10_movetext_interaction → 11_movetext_interaction}/error.tsx +0 -0
  136. /package/test/graphic_test_app/{10_movetext_interaction → 11_movetext_interaction}/select_moves.tsx +0 -0
@@ -41,6 +41,7 @@ interface MovetextImplProps {
41
41
  flipped?: ChessboardProps['flipped'],
42
42
  squareSize?: ChessboardProps['squareSize'],
43
43
  coordinateVisible?: ChessboardProps['coordinateVisible'],
44
+ turnVisible?: ChessboardProps['turnVisible'],
44
45
  colorset?: ChessboardProps['colorset'],
45
46
  pieceset?: ChessboardProps['pieceset'],
46
47
  smallScreenLimits?: ChessboardProps['smallScreenLimits'],
@@ -52,7 +53,7 @@ interface MovetextImplProps {
52
53
  selection?: string;
53
54
  interactionMode?: 'selectMove';
54
55
 
55
- onMoveSelected?: (nodeId: string | undefined, evtOrigin: 'key-first' | 'key-previous' | 'key-next' | 'key-last' | 'click') => void;
56
+ onMoveSelected?: (nodeId: string | undefined, evtOrigin: 'key-first' | 'key-previous' | 'key-next' | 'key-last' | 'key-exit' | 'click') => void;
56
57
  }
57
58
 
58
59
 
@@ -317,6 +318,7 @@ export class MovetextImpl extends React.Component<MovetextImplProps> {
317
318
  flipped={this.props.diagramOptions.flipped}
318
319
  squareSize={this.props.diagramOptions.squareSize}
319
320
  coordinateVisible={this.props.diagramOptions.coordinateVisible}
321
+ turnVisible={this.props.diagramOptions.turnVisible}
320
322
  smallScreenLimits={this.props.diagramOptions.smallScreenLimits}
321
323
  colorset={this.props.diagramOptions.colorset}
322
324
  pieceset={this.props.diagramOptions.pieceset}
@@ -354,32 +356,34 @@ export class MovetextImpl extends React.Component<MovetextImplProps> {
354
356
  }
355
357
 
356
358
  private handleKeyDownInFocusField(evt: React.KeyboardEvent<HTMLAnchorElement>) {
357
- if (evt.key !== 'Home' && evt.key !== 'ArrowLeft' && evt.key !== 'ArrowRight' && evt.key !== 'End') {
359
+ if (evt.key !== 'Home' && evt.key !== 'ArrowLeft' && evt.key !== 'ArrowRight' && evt.key !== 'End' && evt.key !== 'Escape') {
358
360
  return;
359
361
  }
360
362
  evt.preventDefault();
361
363
  if (!this.props.selection) {
362
364
  return;
363
365
  }
364
- let nodeId = undefined;
365
- let evtOrigin: 'key-first' | 'key-previous' | 'key-next' | 'key-last';
366
366
  if (evt.key === 'Home') {
367
- nodeId = firstNodeIdImpl(this.props.game, this.props.selection);
368
- evtOrigin = 'key-first';
367
+ this.fireMoveSelected(firstNodeIdImpl(this.props.game, this.props.selection), 'key-first');
369
368
  }
370
369
  else if (evt.key === 'ArrowLeft') {
371
- nodeId = previousNodeIdImpl(this.props.game, this.props.selection);
372
- evtOrigin = 'key-previous';
370
+ this.fireMoveSelected(previousNodeIdImpl(this.props.game, this.props.selection), 'key-previous');
373
371
  }
374
372
  else if (evt.key === 'ArrowRight') {
375
- nodeId = nextNodeIdImpl(this.props.game, this.props.selection);
376
- evtOrigin = 'key-next';
373
+ this.fireMoveSelected(nextNodeIdImpl(this.props.game, this.props.selection), 'key-next');
377
374
  }
378
- else { // evt.key === 'End'
379
- nodeId = lastNodeIdImpl(this.props.game, this.props.selection);
380
- evtOrigin = 'key-last';
375
+ else if (evt.key === 'End') {
376
+ this.fireMoveSelected(lastNodeIdImpl(this.props.game, this.props.selection), 'key-last');
381
377
  }
382
- if (nodeId && this.props.onMoveSelected) {
378
+ else { // evt.key === 'Escape'
379
+ if (this.props.game.findById(this.props.selection)) {
380
+ this.fireMoveSelected(undefined, 'key-exit');
381
+ }
382
+ }
383
+ }
384
+
385
+ private fireMoveSelected(nodeId: string | undefined, evtOrigin: 'key-first' | 'key-previous' | 'key-next' | 'key-last' | 'key-exit') {
386
+ if ((nodeId || evtOrigin === 'key-exit') && this.props.onMoveSelected) {
383
387
  this.props.onMoveSelected(nodeId, evtOrigin);
384
388
  }
385
389
  }
@@ -33,6 +33,19 @@ export function sanitizeBoolean(input: boolean): boolean {
33
33
  }
34
34
 
35
35
 
36
+ export function sanitizePartialObject<T>(input: Partial<T> | undefined, exceptionBuilder: () => IllegalArgument): Partial<T> {
37
+ if (input === undefined || input === null) {
38
+ return {};
39
+ }
40
+ else if (typeof input !== 'object') {
41
+ throw exceptionBuilder();
42
+ }
43
+ else {
44
+ return input;
45
+ }
46
+ }
47
+
48
+
36
49
  export function sanitizeInteger(input: number, exceptionBuilder: () => IllegalArgument): number {
37
50
  if (typeof input !== 'number' || !Number.isFinite(input)) {
38
51
  throw exceptionBuilder();
package/src/types.ts CHANGED
@@ -20,7 +20,7 @@
20
20
  * -------------------------------------------------------------------------- */
21
21
 
22
22
 
23
- import { Square, SquareCouple, isSquare, isSquareCouple } from 'kokopu';
23
+ import { ColoredPiece, Square, SquareCouple, isColoredPiece, isSquare, isSquareCouple } from 'kokopu';
24
24
 
25
25
  import { IllegalArgument } from './exception';
26
26
 
@@ -36,6 +36,22 @@ export const MIN_SQUARE_SIZE = 12;
36
36
  export const MAX_SQUARE_SIZE = 96;
37
37
 
38
38
 
39
+ /**
40
+ * Type of icon representing a (colored) chess piece.
41
+ *
42
+ * The two special values `'wx'` and `'bx'` correspond to the turn flags.
43
+ */
44
+ export type ChessPieceIconType = ColoredPiece | 'wx' | 'bx';
45
+
46
+
47
+ /**
48
+ * Whether the given object is a {@link ChessPieceIconType} or not.
49
+ */
50
+ export function isChessPieceIconType(iconType: unknown): iconType is ChessPieceIconType {
51
+ return isColoredPiece(iconType) || iconType === 'wx' || iconType === 'bx';
52
+ }
53
+
54
+
39
55
  /**
40
56
  * Set of parameters describing the colors to use to render a {@link Chessboard} component.
41
57
  *
@@ -24,52 +24,106 @@ const { exception, Chessboard } = require('../build/test_headless/index');
24
24
  const test = require('unit.js');
25
25
 
26
26
 
27
- function testAdaptSquareSize(expectedSquareSize, width, height, coordinateVisible, smallScreenLimits) {
28
- test.value(Chessboard.adaptSquareSize(width, height, coordinateVisible, smallScreenLimits)).is(expectedSquareSize);
27
+ function itInvalidArgument(label, action) {
28
+ it(label, () => { test.exception(action).isInstanceOf(exception.IllegalArgument); });
29
+ }
30
+
31
+
32
+ describe('Chessboard.size()', () => {
33
+
34
+ function itChessboardSize(label, expectedWidth, expectedHeight, attr) {
35
+ it(label, () => {
36
+ test.value(Chessboard.size(attr)).is({ width: expectedWidth, height: expectedHeight });
37
+ });
38
+ }
39
+
40
+ itChessboardSize('Default', 374, 333);
41
+ itChessboardSize('Square size 50', 467, 416, { squareSize: 50 });
42
+ itChessboardSize('Default without coordinates', 364, 320, { coordinateVisible: false });
43
+ itChessboardSize('Default without turn', 330, 333, { turnVisible: false });
44
+ itChessboardSize('Default board only', 320, 320, { coordinateVisible: false, turnVisible: false });
45
+
46
+ itInvalidArgument('Attribute not an object', () => Chessboard.size('not-an-object'));
47
+ itInvalidArgument('Square size not an integer', () => Chessboard.size({ squareSize: 'not-an-integer' }));
48
+ itInvalidArgument('Small-screen limits not an array', () => Chessboard.size({ smallScreenLimits: 'not-an-array' }));
49
+ itInvalidArgument('Small-screen limit undefined', () => Chessboard.size({ smallScreenLimits: [ undefined ] }));
50
+ itInvalidArgument('Small-screen limit null', () => Chessboard.size({ smallScreenLimits: [ null ] }));
51
+ itInvalidArgument('Small-screen limit not-an-object', () => Chessboard.size({ smallScreenLimits: [ 'not-an-object' ] }));
52
+ });
29
53
 
30
- const actualSize = Chessboard.size(expectedSquareSize, coordinateVisible, smallScreenLimits);
54
+
55
+ function testAdaptSquareSize(expectedSquareSize, width, height, coordinateVisible, turnVisible, smallScreenLimits) {
56
+
57
+ test.value(Chessboard.adaptSquareSize(width, height, {
58
+ coordinateVisible: coordinateVisible,
59
+ turnVisible: turnVisible,
60
+ smallScreenLimits: smallScreenLimits,
61
+ })).is(expectedSquareSize);
62
+
63
+ const actualSize = Chessboard.size({
64
+ squareSize: expectedSquareSize,
65
+ coordinateVisible: coordinateVisible,
66
+ turnVisible: turnVisible,
67
+ smallScreenLimits: smallScreenLimits,
68
+ });
31
69
  test.value(actualSize.width <= width && actualSize.height <= height).isTrue();
32
70
  }
33
71
 
34
- function testAdaptSquareSizeWithIncrement(expectedSquareSize, width, height, coordinateVisible, smallScreenLimits) {
35
- testAdaptSquareSize(expectedSquareSize, width, height, coordinateVisible, smallScreenLimits);
36
72
 
37
- const actualSizeIncremented = Chessboard.size(expectedSquareSize + 1, coordinateVisible, smallScreenLimits);
73
+ function testAdaptSquareSizeWithIncrement(expectedSquareSize, width, height, coordinateVisible, turnVisible, smallScreenLimits) {
74
+ testAdaptSquareSize(expectedSquareSize, width, height, coordinateVisible, turnVisible, smallScreenLimits);
75
+
76
+ const actualSizeIncremented = Chessboard.size({
77
+ squareSize: expectedSquareSize + 1,
78
+ coordinateVisible: coordinateVisible,
79
+ turnVisible: turnVisible,
80
+ smallScreenLimits: smallScreenLimits,
81
+ });
38
82
  test.value(actualSizeIncremented.width > width || actualSizeIncremented.height > height).isTrue();
39
83
  }
40
84
 
41
- describe('Adapt square-size', () => {
42
-
43
- it('Very small', () => { test.value(Chessboard.adaptSquareSize(10, 10, false)).is(Chessboard.minSquareSize()); });
44
- it('Very large', () => { test.value(Chessboard.adaptSquareSize(9999, 9999, true)).is(Chessboard.maxSquareSize()); });
45
85
 
46
- it('Size 185x300 with coordinates', () => testAdaptSquareSizeWithIncrement(19, 185, 300, true));
47
- it('Size 185x300 without coordinates', () => testAdaptSquareSizeWithIncrement(20, 185, 300, false));
48
- it('Size 300x200 with coordinates', () => testAdaptSquareSizeWithIncrement(23, 300, 200, true));
49
- it('Size 300x200 without coordinates', () => testAdaptSquareSizeWithIncrement(25, 300, 200, false));
50
- it('Size 375x500 with coordinates', () => testAdaptSquareSizeWithIncrement(40, 375, 500, true));
51
- it('Size 375x500 without coordinates', () => testAdaptSquareSizeWithIncrement(41, 375, 500, false));
52
- it('Size 600x450 with coordinates', () => testAdaptSquareSizeWithIncrement(54, 600, 450, true));
53
- it('Size 600x450 without coordinates', () => testAdaptSquareSizeWithIncrement(56, 600, 450, false));
54
-
55
- function itInvalidArgument(label, action) {
56
- it(label, () => { test.exception(action).isInstanceOf(exception.IllegalArgument); });
57
- }
86
+ describe('Adapt square-size', () => {
58
87
 
59
- itInvalidArgument('Width <null>', () => Chessboard.adaptSquareSize(null, 400, true));
60
- itInvalidArgument('Width not-a-number', () => Chessboard.adaptSquareSize('500', 400, false));
61
- itInvalidArgument('Height <undefined>', () => Chessboard.adaptSquareSize(500, undefined, false));
62
- itInvalidArgument('Height object', () => Chessboard.adaptSquareSize(500, {}, true));
88
+ it('Very small', () => { test.value(Chessboard.adaptSquareSize(10, 10, { coordinateVisible: false, turnVisible: false })).is(Chessboard.minSquareSize()); });
89
+ it('Very large', () => { test.value(Chessboard.adaptSquareSize(9999, 9999)).is(Chessboard.maxSquareSize()); });
90
+
91
+ it('Size 185x300 with coordinates & turn', () => testAdaptSquareSizeWithIncrement(19, 185, 300, true, true));
92
+ it('Size 185x300 without coordinates', () => testAdaptSquareSizeWithIncrement(20, 185, 300, false, true));
93
+ it('Size 185x300 without turn', () => testAdaptSquareSizeWithIncrement(22, 185, 300, true, false));
94
+ it('Size 185x300 board only', () => testAdaptSquareSizeWithIncrement(23, 185, 300, false, false));
95
+
96
+ it('Size 300x200 with coordinates & turn', () => testAdaptSquareSizeWithIncrement(23, 300, 200, true, true));
97
+ it('Size 300x200 without coordinates', () => testAdaptSquareSizeWithIncrement(25, 300, 200, false, true));
98
+ it('Size 300x200 without turn', () => testAdaptSquareSizeWithIncrement(23, 300, 200, true, false));
99
+ it('Size 300x200 board only', () => testAdaptSquareSizeWithIncrement(25, 300, 200, false, false));
100
+
101
+ it('Size 375x500 with coordinates & turn', () => testAdaptSquareSizeWithIncrement(40, 375, 500, true, true));
102
+ it('Size 375x500 without coordinates', () => testAdaptSquareSizeWithIncrement(41, 375, 500, false, true));
103
+ it('Size 375x500 without turn', () => testAdaptSquareSizeWithIncrement(45, 375, 500, true, false));
104
+ it('Size 375x500 board only', () => testAdaptSquareSizeWithIncrement(46, 375, 500, false, false));
105
+
106
+ it('Size 600x450 with coordinates & turn', () => testAdaptSquareSizeWithIncrement(54, 600, 450, true, true));
107
+ it('Size 600x450 without coordinates', () => testAdaptSquareSizeWithIncrement(56, 600, 450, false, true));
108
+ it('Size 600x450 without turn', () => testAdaptSquareSizeWithIncrement(54, 600, 450, true, false));
109
+ it('Size 600x450 board only', () => testAdaptSquareSizeWithIncrement(56, 600, 450, false, false));
110
+
111
+ itInvalidArgument('Width <null>', () => Chessboard.adaptSquareSize(null, 400));
112
+ itInvalidArgument('Width not-a-number', () => Chessboard.adaptSquareSize('500', 400));
113
+ itInvalidArgument('Height <undefined>', () => Chessboard.adaptSquareSize(500, undefined));
114
+ itInvalidArgument('Height object', () => Chessboard.adaptSquareSize(500, {}));
115
+ itInvalidArgument('Attribute not-an-object', () => Chessboard.adaptSquareSize(500, 400, 'not-an-object'));
116
+ itInvalidArgument('Small-screen limits not-an-array', () => Chessboard.adaptSquareSize(500, 400, { smallScreenLimits: 'not-an-array' }));
63
117
  });
64
118
 
119
+
65
120
  describe('Adapt square-size with small-screen limits', () => {
66
121
 
67
122
  const limits = [
68
- { width: 470, squareSize: 12, coordinateVisible: false },
69
- { width: 540, squareSize: 16, coordinateVisible: false },
70
- { width: 620, squareSize: 24, coordinateVisible: false },
123
+ { width: 540, squareSize: 24, turnVisible: false },
124
+ { width: 620, squareSize: 28, coordinateVisible: false },
71
125
  { width: 730, squareSize: 32 },
72
- { width: 860, squareSize: 44 },
126
+ { width: 860, squareSize: 48 },
73
127
  ];
74
128
 
75
129
  before(() => {
@@ -81,18 +135,32 @@ describe('Adapt square-size with small-screen limits', () => {
81
135
 
82
136
  it('Window-limited', () => {
83
137
  window.innerWidth = 640;
84
- testAdaptSquareSize(32, 9999, 9999, true, limits);
138
+ testAdaptSquareSize(32, 9999, 9999, true, true, limits);
85
139
  });
86
- it('Available-space-limited 1', () => {
140
+
141
+ it('Available-space-limited with coordinates & turn', () => {
87
142
  window.innerWidth = 800;
88
- testAdaptSquareSize(40, 375, 500, true, limits);
143
+ testAdaptSquareSize(40, 375, 500, true, true, limits);
89
144
  });
90
- it('Available-space-limited 2', () => {
145
+ it('Available-space-limited without coordinates', () => {
91
146
  window.innerWidth = 800;
92
- testAdaptSquareSize(41, 375, 500, false, limits);
147
+ testAdaptSquareSize(41, 375, 500, false, true, limits);
93
148
  });
149
+ it('Available-space-limited without turn', () => {
150
+ window.innerWidth = 800;
151
+ testAdaptSquareSize(45, 375, 500, true, false, limits);
152
+ });
153
+ it('Available-space-limited board only', () => {
154
+ window.innerWidth = 800;
155
+ testAdaptSquareSize(46, 375, 500, false, false, limits);
156
+ });
157
+
94
158
  it('Force hidden coordinates', () => {
95
159
  window.innerWidth = 600;
96
- testAdaptSquareSize(20, 185, 300, true, limits);
160
+ testAdaptSquareSize(20, 185, 300, true, true, limits);
161
+ });
162
+ it('Force hidden coordinates & turn', () => {
163
+ window.innerWidth = 500;
164
+ testAdaptSquareSize(23, 185, 300, true, true, limits);
97
165
  });
98
166
  });
@@ -23,9 +23,9 @@
23
23
  const { describeWithBrowser, itChecksScreenshots } = require('./common/graphic');
24
24
 
25
25
 
26
- describeWithBrowser('Marker icons graphic', browserContext => {
26
+ describeWithBrowser('Icons graphic', browserContext => {
27
27
 
28
- itChecksScreenshots(browserContext, '04_marker_icons_graphic/base', [
28
+ itChecksScreenshots(browserContext, '04_icons_graphic/marker', [
29
29
 
30
30
  'default square',
31
31
  'colorized square',
@@ -46,4 +46,16 @@ describeWithBrowser('Marker icons graphic', browserContext => {
46
46
  'invalid arrow size',
47
47
  ]);
48
48
 
49
+ itChecksScreenshots(browserContext, '04_icons_graphic/chess_piece', [
50
+
51
+ 'single piece',
52
+ 'multiple pieces',
53
+ 'customized pieceset',
54
+
55
+ 'invalid size',
56
+ 'invalid single piece',
57
+ 'invalid multiple pieces',
58
+ 'invalid pieceset',
59
+ ]);
60
+
49
61
  });
@@ -0,0 +1,50 @@
1
+ /* -------------------------------------------------------------------------- *
2
+ * *
3
+ * This file is part of Kokopu-React, a JavaScript chess library. *
4
+ * Copyright (C) 2021-2023 Yoann Le Montagner <yo35 -at- melix.net> *
5
+ * *
6
+ * This program is free software: you can redistribute it and/or *
7
+ * modify it under the terms of the GNU Lesser General Public License *
8
+ * as published by the Free Software Foundation, either version 3 of *
9
+ * the License, or (at your option) any later version. *
10
+ * *
11
+ * This program is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
+ * GNU Lesser General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU Lesser General *
17
+ * Public License along with this program. If not, see *
18
+ * <http://www.gnu.org/licenses/>. *
19
+ * *
20
+ * -------------------------------------------------------------------------- */
21
+
22
+
23
+ const { describeWithBrowser, itCustom, itChecksScreenshots, takeScreenshot, compareScreenshot, setWindowWidth } = require('./common/graphic');
24
+
25
+
26
+ describeWithBrowser('Chessboard on small-screens', browserContext => {
27
+
28
+ itChecksScreenshots(browserContext, '09_chessboard_small_screens/base', [
29
+ 'default',
30
+ 'invalid limits',
31
+ ]);
32
+
33
+ function itCheckScreenshotWithWidth(width) {
34
+ const label = `width ${width}`;
35
+ itCustom(browserContext, '09_chessboard_small_screens/base', 0, label, async element => {
36
+ await setWindowWidth(browserContext, width);
37
+ await takeScreenshot(browserContext, label, element);
38
+ await compareScreenshot(browserContext, label);
39
+ });
40
+ }
41
+
42
+ itCheckScreenshotWithWidth(750);
43
+ itCheckScreenshotWithWidth(740);
44
+ itCheckScreenshotWithWidth(730);
45
+ itCheckScreenshotWithWidth(720);
46
+ itCheckScreenshotWithWidth(710);
47
+ itCheckScreenshotWithWidth(700);
48
+ itCheckScreenshotWithWidth(690);
49
+
50
+ });
@@ -25,14 +25,14 @@ const { describeWithBrowser, itChecksScreenshots } = require('./common/graphic')
25
25
 
26
26
  describeWithBrowser('Movetext graphic', browserContext => {
27
27
 
28
- itChecksScreenshots(browserContext, '09_movetext_graphic/base', [
28
+ itChecksScreenshots(browserContext, '10_movetext_graphic/base', [
29
29
  'game 1',
30
30
  'game 2',
31
31
  'game 3',
32
32
  'game 4',
33
33
  ]);
34
34
 
35
- itChecksScreenshots(browserContext, '09_movetext_graphic/error', [
35
+ itChecksScreenshots(browserContext, '10_movetext_graphic/error', [
36
36
  'wrong game index 1',
37
37
  'wrong game index 2',
38
38
  'pgn parsing error 1',
@@ -41,16 +41,17 @@ describeWithBrowser('Movetext graphic', browserContext => {
41
41
  'wrong game index type',
42
42
  ]);
43
43
 
44
- itChecksScreenshots(browserContext, '09_movetext_graphic/html', [
44
+ itChecksScreenshots(browserContext, '10_movetext_graphic/html', [
45
45
  'html in headers',
46
46
  'html in comments',
47
47
  'filtered tags and attributes',
48
48
  ]);
49
49
 
50
- itChecksScreenshots(browserContext, '09_movetext_graphic/options', [
50
+ itChecksScreenshots(browserContext, '10_movetext_graphic/options', [
51
51
  'localized piece symbols',
52
52
  'custom piece symbols',
53
53
  'figurine piece symbols and diagram options',
54
+ 'other diagram options',
54
55
  'hidden diagrams',
55
56
  'wrong diagram options 1',
56
57
  'wrong diagram options 2',
@@ -22,12 +22,13 @@
22
22
 
23
23
  const { describeWithBrowser, itCustom, setSandbox, compareSandbox, takeScreenshot, compareScreenshot, itChecksScreenshots } = require('./common/graphic');
24
24
  const { By, Key } = require('selenium-webdriver');
25
+ const test = require('unit.js');
25
26
 
26
27
 
27
28
  describeWithBrowser('Movetext interaction', browserContext => {
28
29
 
29
30
  function itCheckClickMove(itemIndex, label, targets) {
30
- itCustom(browserContext, '10_movetext_interaction/select_moves', itemIndex, label, async element => {
31
+ itCustom(browserContext, '11_movetext_interaction/select_moves', itemIndex, label, async element => {
31
32
  const actions = browserContext.driver.actions({ async: true });
32
33
  await setSandbox(browserContext, '');
33
34
  for (let i = 0; i < targets.length; ++i) {
@@ -61,9 +62,22 @@ describeWithBrowser('Movetext interaction', browserContext => {
61
62
  { searchedText: 'Nc6', expectedText: tpl('1b-v0-2b', 'click') },
62
63
  ]);
63
64
 
64
- function itCheckKeyboardActions(itemIndex, label, expectedOnGoFirst, expectedOnGoPrevious, expectedOnGoNext, expectedOnGoLast) {
65
- itCustom(browserContext, '10_movetext_interaction/select_moves', itemIndex, label, async element => {
66
- const focusFieldElement = await element.findElement(By.className('kokopu-focusField'));
65
+ function itCheckKeyboardActions(itemIndex, label, expectedOnGoFirst, expectedOnGoPrevious, expectedOnGoNext, expectedOnGoLast, expectedOnExit) {
66
+ itCustom(browserContext, '11_movetext_interaction/select_moves', itemIndex, label, async element => {
67
+ const focusFieldElements = await element.findElements(By.className('kokopu-focusField'));
68
+
69
+ // Handle components for which no interaction is defined.
70
+ if (focusFieldElements.length === 0) {
71
+ test.value('').is(expectedOnGoFirst);
72
+ test.value('').is(expectedOnGoPrevious);
73
+ test.value('').is(expectedOnGoNext);
74
+ test.value('').is(expectedOnGoLast);
75
+ test.value('').is(expectedOnExit);
76
+ return;
77
+ }
78
+
79
+ test.value(focusFieldElements.length).is(1);
80
+ const focusFieldElement = focusFieldElements[0];
67
81
 
68
82
  await setSandbox(browserContext, '');
69
83
  await focusFieldElement.sendKeys(Key.HOME);
@@ -81,22 +95,32 @@ describeWithBrowser('Movetext interaction', browserContext => {
81
95
  await focusFieldElement.sendKeys(Key.END);
82
96
  await compareSandbox(browserContext, expectedOnGoLast);
83
97
 
98
+ await setSandbox(browserContext, '');
99
+ await focusFieldElement.sendKeys(Key.ESCAPE);
100
+ await compareSandbox(browserContext, expectedOnExit);
101
+
84
102
  await setSandbox(browserContext, '');
85
103
  await focusFieldElement.sendKeys(Key.ARROW_UP);
86
104
  await compareSandbox(browserContext, '');
87
105
  });
88
106
  }
89
107
 
90
- itCheckKeyboardActions(1, 'key on unselected', '', '', '', '');
91
- itCheckKeyboardActions(2, 'key on with variations 1', tpl('start', 'key-first'), tpl('1b-v0-2b', 'key-previous'), tpl('1b-v0-3w-v0-3b', 'key-next'), tpl('1b-v0-3w-v0-4w', 'key-last'));
92
- itCheckKeyboardActions(3, 'key on with variations 2', tpl('start', 'key-first'), tpl('1b-v0-2w', 'key-previous'), tpl('1b-v0-3w', 'key-next'), tpl('1b-v0-3w', 'key-last'));
93
- itCheckKeyboardActions(4, 'key on start selected', '', '', tpl('1w', 'key-next'), tpl('6b', 'key-last'));
94
- itCheckKeyboardActions(5, 'key on first selected', tpl('start', 'key-first'), tpl('start', 'key-previous'), tpl('1b', 'key-next'), tpl('6b', 'key-last'));
95
- itCheckKeyboardActions(6, 'key on last selected', tpl('start', 'key-first'), tpl('6w', 'key-previous'), '', '');
96
- itCheckKeyboardActions(7, 'key on invalid selection', '', '', '', '');
97
- itCheckKeyboardActions(8, 'key on sub-variation selected', tpl('start', 'key-first'), tpl('1w', 'key-previous'), tpl('1b-v0-1b', 'key-next'), tpl('1b-v0-3w', 'key-last'));
98
-
99
- itChecksScreenshots(browserContext, '10_movetext_interaction/error', [
108
+ const TPL_EXIT = tpl(undefined, 'key-exit');
109
+
110
+ itCheckKeyboardActions(0, 'key on disabled', '', '', '', '', '');
111
+ itCheckKeyboardActions(1, 'key on unselected', '', '', '', '', '');
112
+ itCheckKeyboardActions(2, 'key on with variations 1', tpl('start', 'key-first'), tpl('1b-v0-2b', 'key-previous'), tpl('1b-v0-3w-v0-3b', 'key-next'),
113
+ tpl('1b-v0-3w-v0-4w', 'key-last'), TPL_EXIT);
114
+ itCheckKeyboardActions(3, 'key on with variations 2', tpl('start', 'key-first'), tpl('1b-v0-2w', 'key-previous'), tpl('1b-v0-3w', 'key-next'),
115
+ tpl('1b-v0-3w', 'key-last'), TPL_EXIT);
116
+ itCheckKeyboardActions(4, 'key on start selected', '', '', tpl('1w', 'key-next'), tpl('6b', 'key-last'), TPL_EXIT);
117
+ itCheckKeyboardActions(5, 'key on first selected', tpl('start', 'key-first'), tpl('start', 'key-previous'), tpl('1b', 'key-next'), tpl('6b', 'key-last'), TPL_EXIT);
118
+ itCheckKeyboardActions(6, 'key on last selected', tpl('start', 'key-first'), tpl('6w', 'key-previous'), '', '', TPL_EXIT);
119
+ itCheckKeyboardActions(7, 'key on invalid selection', '', '', '', '', '');
120
+ itCheckKeyboardActions(8, 'key on sub-variation selected', tpl('start', 'key-first'), tpl('1w', 'key-previous'), tpl('1b-v0-1b', 'key-next'),
121
+ tpl('1b-v0-3w', 'key-last'), TPL_EXIT);
122
+
123
+ itChecksScreenshots(browserContext, '11_movetext_interaction/error', [
100
124
  'wrong interaction mode',
101
125
  ]);
102
126
 
@@ -204,6 +204,15 @@ exports.setSandbox = async function(browserContext, value) {
204
204
  };
205
205
 
206
206
 
207
+ /**
208
+ * Set the width of the browser.
209
+ */
210
+ exports.setWindowWidth = async function(browserContext, width) {
211
+ const { height } = await await browserContext.driver.manage().window().getRect();
212
+ await browserContext.driver.manage().window().setRect({ width: width, height: height });
213
+ };
214
+
215
+
207
216
  /**
208
217
  * Open the page corresponding to the given test-case, and execute the given scenario.
209
218
  */
@@ -0,0 +1,38 @@
1
+ /* -------------------------------------------------------------------------- *
2
+ * *
3
+ * This file is part of Kokopu-React, a JavaScript chess library. *
4
+ * Copyright (C) 2021-2023 Yoann Le Montagner <yo35 -at- melix.net> *
5
+ * *
6
+ * This program is free software: you can redistribute it and/or *
7
+ * modify it under the terms of the GNU Lesser General Public License *
8
+ * as published by the Free Software Foundation, either version 3 of *
9
+ * the License, or (at your option) any later version. *
10
+ * *
11
+ * This program is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
+ * GNU Lesser General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU Lesser General *
17
+ * Public License along with this program. If not, see *
18
+ * <http://www.gnu.org/licenses/>. *
19
+ * *
20
+ * -------------------------------------------------------------------------- */
21
+
22
+
23
+ import * as React from 'react';
24
+ import { testApp } from '../common/test_app';
25
+ import { ChessPieceIcon } from '../../../dist/lib/index';
26
+
27
+ testApp([ /* eslint-disable react/jsx-key */
28
+
29
+ <ChessPieceIcon size={44} type="wq" />,
30
+ <ChessPieceIcon size={24} type={[ 'bb', 'wx', 'wx', 'wn', 'bx', 'bk', 'bk' ]} />,
31
+ <ChessPieceIcon size={36} type={[ 'wr', 'wb', 'bq' ]} pieceset="eyes" />,
32
+
33
+ <ChessPieceIcon size={ /* eslint-disable @typescript-eslint/no-explicit-any */ 'not-a-number' as any /* eslint-enable @typescript-eslint/no-explicit-any */ } type="wq" />,
34
+ <ChessPieceIcon size={40} type={ /* eslint-disable @typescript-eslint/no-explicit-any */ 'invalid' as any /* eslint-enable @typescript-eslint/no-explicit-any */ } />,
35
+ <ChessPieceIcon size={40} type={[ 'bb', /* eslint-disable @typescript-eslint/no-explicit-any */ 'zp' as any /* eslint-enable @typescript-eslint/no-explicit-any */ ]} />,
36
+ <ChessPieceIcon size={40} type="wq" pieceset="not-a-pieceset" />,
37
+
38
+ ]); /* eslint-enable react/jsx-key */