kokopu-react 1.5.2 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  ChangeLog
2
2
  =========
3
3
 
4
+ 1.5.3 (April 30, 2022)
5
+ ----------------------
6
+ * Add method `Movetext#focus()`.
7
+ * Expose static methods `Movetext#firstNodeId(..)`, `Movetext#previousNodeId(..)`, `Movetext#nextNodeId(..)`
8
+ and `Movetext#lastNodeId(..)`.
9
+
4
10
  1.5.2 (April 29, 2022)
5
11
  ----------------------
6
12
  * Prevent default actions when handling key events in component `Movetext`.
@@ -523,46 +523,35 @@ var Movetext = /*#__PURE__*/function (_React$Component) {
523
523
  }, {
524
524
  key: "handleKeyDownInFocusField",
525
525
  value: function handleKeyDownInFocusField(evt) {
526
- if (evt.key === 'Home' || evt.key === 'ArrowLeft' || evt.key === 'ArrowRight' || evt.key === 'End') {
527
- evt.preventDefault();
526
+ if (evt.key !== 'Home' && evt.key !== 'ArrowLeft' && evt.key !== 'ArrowRight' && evt.key !== 'End') {
527
+ return;
528
528
  }
529
529
 
530
+ evt.preventDefault();
531
+
530
532
  if (!this.props.selection) {
531
533
  return;
532
534
  }
533
535
 
534
- var game = parseGame(this.props.game, this.props.gameIndex).game;
535
- var nodeId = false;
536
+ var _parseGame = parseGame(this.props.game, this.props.gameIndex),
537
+ game = _parseGame.game;
538
+
539
+ var nodeId = undefined;
536
540
  var evtOrigin = '';
537
541
 
538
- if (this.props.selection === 'start') {
539
- if (evt.key === 'ArrowRight') {
540
- nodeId = getNextNodeId(game.mainVariation(), true);
541
- evtOrigin = 'key-next';
542
- } else if (evt.key === 'End') {
543
- nodeId = getLastNodeId(game.mainVariation(), true);
544
- evtOrigin = 'key-last';
545
- }
542
+ if (evt.key === 'Home') {
543
+ nodeId = Movetext.firstNodeId(game, this.props.selection);
544
+ evtOrigin = 'key-first';
545
+ } else if (evt.key === 'ArrowLeft') {
546
+ nodeId = Movetext.previousNodeId(game, this.props.selection);
547
+ evtOrigin = 'key-previous';
548
+ } else if (evt.key === 'ArrowRight') {
549
+ nodeId = Movetext.nextNodeId(game, this.props.selection);
550
+ evtOrigin = 'key-next';
546
551
  } else {
547
- var currentNode = game.findById(this.props.selection);
548
-
549
- if (!currentNode) {
550
- return;
551
- }
552
-
553
- if (evt.key === 'Home') {
554
- nodeId = 'start';
555
- evtOrigin = 'key-first';
556
- } else if (evt.key === 'ArrowLeft') {
557
- nodeId = getPreviousNodeId(currentNode);
558
- evtOrigin = 'key-previous';
559
- } else if (evt.key === 'ArrowRight') {
560
- nodeId = getNextNodeId(currentNode, false);
561
- evtOrigin = 'key-next';
562
- } else if (evt.key === 'End') {
563
- nodeId = getLastNodeId(currentNode, false);
564
- evtOrigin = 'key-last';
565
- }
552
+ // evt.key === 'End'
553
+ nodeId = Movetext.lastNodeId(game, this.props.selection);
554
+ evtOrigin = 'key-last';
566
555
  }
567
556
 
568
557
  if (nodeId && this.props.onMoveSelected) {
@@ -572,7 +561,7 @@ var Movetext = /*#__PURE__*/function (_React$Component) {
572
561
  }, {
573
562
  key: "handleNodeClicked",
574
563
  value: function handleNodeClicked(nodeId) {
575
- this.focusFieldRef.current.focus();
564
+ this.focus();
576
565
 
577
566
  if (this.props.onMoveSelected) {
578
567
  this.props.onMoveSelected(nodeId === this.props.selection ? undefined : nodeId, 'click');
@@ -612,6 +601,139 @@ var Movetext = /*#__PURE__*/function (_React$Component) {
612
601
  };
613
602
  }
614
603
  }
604
+ /**
605
+ * Set the focus to the current component.
606
+ *
607
+ * @public
608
+ */
609
+
610
+ }, {
611
+ key: "focus",
612
+ value: function focus() {
613
+ this.focusFieldRef.current.focus();
614
+ }
615
+ /**
616
+ * Return the ID of the main variation in the given chess game.
617
+ * If the given selection corresponds already at the main variation, `undefined` is returned.
618
+ *
619
+ * This corresponds to the operation performed when the user presses key "home" on a `Movetext` component.
620
+ *
621
+ * @param {kokopu.Game} game Considered chess game.
622
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
623
+ * @returns {string?}
624
+ * @public
625
+ */
626
+
627
+ }], [{
628
+ key: "firstNodeId",
629
+ value: function firstNodeId(game, selection) {
630
+ if (!game.findById(selection)) {
631
+ return undefined;
632
+ }
633
+
634
+ return selection === 'start' ? undefined : 'start';
635
+ }
636
+ /**
637
+ * Return the ID of the node immediately preceding the given selection in the given chess game.
638
+ * If no such node exists, `undefined` is returned.
639
+ *
640
+ * This corresponds to the operation performed when the user presses key "arrow left" on a `Movetext` component.
641
+ *
642
+ * @param {kokopu.Game} game Considered chess game.
643
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
644
+ * @returns {string?}
645
+ * @public
646
+ */
647
+
648
+ }, {
649
+ key: "previousNodeId",
650
+ value: function previousNodeId(game, selection) {
651
+ var currentNode = game.findById(selection);
652
+
653
+ if (!currentNode) {
654
+ return undefined;
655
+ }
656
+
657
+ if (selection === 'start') {
658
+ return undefined;
659
+ } else if (selection.endsWith('start')) {
660
+ currentNode = currentNode.parentNode(); // `.parentNode()` returns always non-null ref here
661
+ }
662
+
663
+ while (currentNode) {
664
+ var previousNode = currentNode.previous();
665
+
666
+ if (previousNode) {
667
+ return previousNode.id();
668
+ }
669
+
670
+ currentNode = currentNode.parentVariation().parentNode();
671
+ }
672
+
673
+ return 'start';
674
+ }
675
+ /**
676
+ * Return the ID of the node immediately following the given selection in the given chess game.
677
+ * If no such node exists, `undefined` is returned.
678
+ *
679
+ * This corresponds to the operation performed when the user presses key "arrow right" on a `Movetext` component.
680
+ *
681
+ * @param {kokopu.Game} game Considered chess game.
682
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
683
+ * @returns {string?}
684
+ * @public
685
+ */
686
+
687
+ }, {
688
+ key: "nextNodeId",
689
+ value: function nextNodeId(game, selection) {
690
+ var currentNode = game.findById(selection);
691
+
692
+ if (!currentNode) {
693
+ return undefined;
694
+ }
695
+
696
+ var nextNode = selection.endsWith('start') ? currentNode.first() : currentNode.next();
697
+ return nextNode ? nextNode.id() : undefined;
698
+ }
699
+ /**
700
+ * Return the ID of the node at then end of the variation in which lies the given selection in the given chess game.
701
+ * If the selection is already at the end its variation, `undefined` is returned.
702
+ *
703
+ * This corresponds to the operation performed when the user presses key "end" on a `Movetext` component.
704
+ *
705
+ * @param {kokopu.Game} game Considered chess game.
706
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
707
+ * @returns {string?}
708
+ * @public
709
+ */
710
+
711
+ }, {
712
+ key: "lastNodeId",
713
+ value: function lastNodeId(game, selection) {
714
+ var currentNode = game.findById(selection);
715
+
716
+ if (!currentNode) {
717
+ return undefined;
718
+ }
719
+
720
+ currentNode = selection.endsWith('start') ? currentNode.first() : currentNode.next();
721
+
722
+ if (!currentNode) {
723
+ // Ensure that the input node is not already the last one.
724
+ return undefined;
725
+ }
726
+
727
+ while (true) {
728
+ var nextNode = currentNode.next();
729
+
730
+ if (!nextNode) {
731
+ return currentNode.id();
732
+ }
733
+
734
+ currentNode = nextNode;
735
+ }
736
+ }
615
737
  }]);
616
738
 
617
739
  return Movetext;
@@ -779,41 +901,6 @@ function figurineNotation(text, fontName) {
779
901
 
780
902
  return result;
781
903
  }
782
-
783
- function getPreviousNodeId(currentNode) {
784
- var previousNode = currentNode.previous();
785
-
786
- if (previousNode) {
787
- return previousNode.id();
788
- } else {
789
- var parentNode = currentNode.parentVariation().parentNode();
790
- return parentNode ? getPreviousNodeId(parentNode) : 'start';
791
- }
792
- }
793
-
794
- function getNextNodeId(currentNode, isVariation) {
795
- var nextNode = isVariation ? currentNode.first() : currentNode.next();
796
- return nextNode ? nextNode.id() : false;
797
- }
798
-
799
- function getLastNodeId(currentNode, isVariation) {
800
- currentNode = isVariation ? currentNode.first() : currentNode.next();
801
-
802
- if (!currentNode) {
803
- // Ensure that the input node is not already the last one.
804
- return false;
805
- }
806
-
807
- while (true) {
808
- var nextNode = currentNode.next();
809
-
810
- if (!nextNode) {
811
- return currentNode.id();
812
- }
813
-
814
- currentNode = nextNode;
815
- }
816
- }
817
904
  /**
818
905
  * Try to interpret the given object as a chess game.
819
906
  */
@@ -39,4 +39,5 @@ testApp([ /* eslint-disable react/jsx-key */
39
39
  <Movetext game={pgn} gameIndex={7} headerVisible={false} onMoveSelected={onMoveSelected} interactionMode="selectMove" selection="1w" />,
40
40
  <Movetext game={pgn} gameIndex={7} headerVisible={false} onMoveSelected={onMoveSelected} interactionMode="selectMove" selection="6b" />,
41
41
  <Movetext game={pgn} gameIndex={7} headerVisible={false} onMoveSelected={onMoveSelected} interactionMode="selectMove" selection="invalid-id" />,
42
+ <Movetext game={pgn} gameIndex={8} headerVisible={false} onMoveSelected={onMoveSelected} interactionMode="selectMove" selection="1b-v0-start" />,
42
43
  ], 'width-600'); /* eslint-enable react/jsx-key */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kokopu-react",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "A React-based library to create and display chessboard components.",
5
5
  "keywords": [
6
6
  "chess",
package/src/Movetext.js CHANGED
@@ -331,46 +331,31 @@ export default class Movetext extends React.Component {
331
331
  }
332
332
 
333
333
  handleKeyDownInFocusField(evt) {
334
- if (evt.key === 'Home' || evt.key === 'ArrowLeft' || evt.key === 'ArrowRight' || evt.key === 'End') {
335
- evt.preventDefault();
334
+ if (evt.key !== 'Home' && evt.key !== 'ArrowLeft' && evt.key !== 'ArrowRight' && evt.key !== 'End') {
335
+ return;
336
336
  }
337
+ evt.preventDefault();
337
338
  if (!this.props.selection) {
338
339
  return;
339
340
  }
340
- let game = parseGame(this.props.game, this.props.gameIndex).game;
341
- let nodeId = false;
341
+ let { game } = parseGame(this.props.game, this.props.gameIndex);
342
+ let nodeId = undefined;
342
343
  let evtOrigin = '';
343
- if (this.props.selection === 'start') {
344
- if (evt.key === 'ArrowRight') {
345
- nodeId = getNextNodeId(game.mainVariation(), true);
346
- evtOrigin = 'key-next';
347
- }
348
- else if (evt.key === 'End') {
349
- nodeId = getLastNodeId(game.mainVariation(), true);
350
- evtOrigin = 'key-last';
351
- }
344
+ if (evt.key === 'Home') {
345
+ nodeId = Movetext.firstNodeId(game, this.props.selection);
346
+ evtOrigin = 'key-first';
352
347
  }
353
- else {
354
- let currentNode = game.findById(this.props.selection);
355
- if (!currentNode) {
356
- return;
357
- }
358
- if (evt.key === 'Home') {
359
- nodeId = 'start';
360
- evtOrigin = 'key-first';
361
- }
362
- else if (evt.key === 'ArrowLeft') {
363
- nodeId = getPreviousNodeId(currentNode);
364
- evtOrigin = 'key-previous';
365
- }
366
- else if (evt.key === 'ArrowRight') {
367
- nodeId = getNextNodeId(currentNode, false);
368
- evtOrigin = 'key-next';
369
- }
370
- else if (evt.key === 'End') {
371
- nodeId = getLastNodeId(currentNode, false);
372
- evtOrigin = 'key-last';
373
- }
348
+ else if (evt.key === 'ArrowLeft') {
349
+ nodeId = Movetext.previousNodeId(game, this.props.selection);
350
+ evtOrigin = 'key-previous';
351
+ }
352
+ else if (evt.key === 'ArrowRight') {
353
+ nodeId = Movetext.nextNodeId(game, this.props.selection);
354
+ evtOrigin = 'key-next';
355
+ }
356
+ else { // evt.key === 'End'
357
+ nodeId = Movetext.lastNodeId(game, this.props.selection);
358
+ evtOrigin = 'key-last';
374
359
  }
375
360
  if (nodeId && this.props.onMoveSelected) {
376
361
  this.props.onMoveSelected(nodeId, evtOrigin);
@@ -378,7 +363,7 @@ export default class Movetext extends React.Component {
378
363
  }
379
364
 
380
365
  handleNodeClicked(nodeId) {
381
- this.focusFieldRef.current.focus();
366
+ this.focus();
382
367
  if (this.props.onMoveSelected) {
383
368
  this.props.onMoveSelected(nodeId === this.props.selection ? undefined : nodeId, 'click');
384
369
  }
@@ -403,6 +388,114 @@ export default class Movetext extends React.Component {
403
388
  return notation => notation;
404
389
  }
405
390
  }
391
+
392
+ /**
393
+ * Set the focus to the current component.
394
+ *
395
+ * @public
396
+ */
397
+ focus() {
398
+ this.focusFieldRef.current.focus();
399
+ }
400
+
401
+ /**
402
+ * Return the ID of the main variation in the given chess game.
403
+ * If the given selection corresponds already at the main variation, `undefined` is returned.
404
+ *
405
+ * This corresponds to the operation performed when the user presses key "home" on a `Movetext` component.
406
+ *
407
+ * @param {kokopu.Game} game Considered chess game.
408
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
409
+ * @returns {string?}
410
+ * @public
411
+ */
412
+ static firstNodeId(game, selection) {
413
+ if (!game.findById(selection)) {
414
+ return undefined;
415
+ }
416
+ return selection === 'start' ? undefined : 'start';
417
+ }
418
+
419
+ /**
420
+ * Return the ID of the node immediately preceding the given selection in the given chess game.
421
+ * If no such node exists, `undefined` is returned.
422
+ *
423
+ * This corresponds to the operation performed when the user presses key "arrow left" on a `Movetext` component.
424
+ *
425
+ * @param {kokopu.Game} game Considered chess game.
426
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
427
+ * @returns {string?}
428
+ * @public
429
+ */
430
+ static previousNodeId(game, selection) {
431
+ let currentNode = game.findById(selection);
432
+ if (!currentNode) {
433
+ return undefined;
434
+ }
435
+ if (selection === 'start') {
436
+ return undefined;
437
+ }
438
+ else if (selection.endsWith('start')) {
439
+ currentNode = currentNode.parentNode(); // `.parentNode()` returns always non-null ref here
440
+ }
441
+ while (currentNode) {
442
+ let previousNode = currentNode.previous();
443
+ if (previousNode) {
444
+ return previousNode.id();
445
+ }
446
+ currentNode = currentNode.parentVariation().parentNode();
447
+ }
448
+ return 'start';
449
+ }
450
+
451
+ /**
452
+ * Return the ID of the node immediately following the given selection in the given chess game.
453
+ * If no such node exists, `undefined` is returned.
454
+ *
455
+ * This corresponds to the operation performed when the user presses key "arrow right" on a `Movetext` component.
456
+ *
457
+ * @param {kokopu.Game} game Considered chess game.
458
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
459
+ * @returns {string?}
460
+ * @public
461
+ */
462
+ static nextNodeId(game, selection) {
463
+ let currentNode = game.findById(selection);
464
+ if (!currentNode) {
465
+ return undefined;
466
+ }
467
+ let nextNode = selection.endsWith('start') ? currentNode.first() : currentNode.next();
468
+ return nextNode ? nextNode.id() : undefined;
469
+ }
470
+
471
+ /**
472
+ * Return the ID of the node at then end of the variation in which lies the given selection in the given chess game.
473
+ * If the selection is already at the end its variation, `undefined` is returned.
474
+ *
475
+ * This corresponds to the operation performed when the user presses key "end" on a `Movetext` component.
476
+ *
477
+ * @param {kokopu.Game} game Considered chess game.
478
+ * @param {string} selection ID of the selected move (or `'start'` for the beginning of the main variation).
479
+ * @returns {string?}
480
+ * @public
481
+ */
482
+ static lastNodeId(game, selection) {
483
+ let currentNode = game.findById(selection);
484
+ if (!currentNode) {
485
+ return undefined;
486
+ }
487
+ currentNode = selection.endsWith('start') ? currentNode.first() : currentNode.next();
488
+ if (!currentNode) { // Ensure that the input node is not already the last one.
489
+ return undefined;
490
+ }
491
+ while (true) {
492
+ let nextNode = currentNode.next();
493
+ if (!nextNode) {
494
+ return currentNode.id();
495
+ }
496
+ currentNode = nextNode;
497
+ }
498
+ }
406
499
  }
407
500
 
408
501
 
@@ -569,39 +662,6 @@ function figurineNotation(text, fontName) {
569
662
  }
570
663
 
571
664
 
572
- function getPreviousNodeId(currentNode) {
573
- let previousNode = currentNode.previous();
574
- if (previousNode) {
575
- return previousNode.id();
576
- }
577
- else {
578
- let parentNode = currentNode.parentVariation().parentNode();
579
- return parentNode ? getPreviousNodeId(parentNode) : 'start';
580
- }
581
- }
582
-
583
-
584
- function getNextNodeId(currentNode, isVariation) {
585
- let nextNode = isVariation ? currentNode.first() : currentNode.next();
586
- return nextNode ? nextNode.id() : false;
587
- }
588
-
589
-
590
- function getLastNodeId(currentNode, isVariation) {
591
- currentNode = isVariation ? currentNode.first() : currentNode.next();
592
- if (!currentNode) { // Ensure that the input node is not already the last one.
593
- return false;
594
- }
595
- while (true) {
596
- let nextNode = currentNode.next();
597
- if (!nextNode) {
598
- return currentNode.id();
599
- }
600
- currentNode = nextNode;
601
- }
602
- }
603
-
604
-
605
665
  /**
606
666
  * Try to interpret the given object as a chess game.
607
667
  */
@@ -90,6 +90,10 @@ describe('Movetext interaction', function() {
90
90
  await setSandbox(browserContext, '');
91
91
  await focusFieldElement.sendKeys(Key.END);
92
92
  await compareSandbox(browserContext, expectedOnGoLast);
93
+
94
+ await setSandbox(browserContext, '');
95
+ await focusFieldElement.sendKeys(Key.ARROW_UP);
96
+ await compareSandbox(browserContext, '');
93
97
  });
94
98
  }
95
99
 
@@ -100,4 +104,5 @@ describe('Movetext interaction', function() {
100
104
  itCheckKeyboardActions(5, 'key on first selected', tpl('start', 'key-first'), tpl('start', 'key-previous'), tpl('1b', 'key-next'), tpl('6b', 'key-last'));
101
105
  itCheckKeyboardActions(6, 'key on last selected', tpl('start', 'key-first'), tpl('6w', 'key-previous'), '', '');
102
106
  itCheckKeyboardActions(7, 'key on invalid selection', '', '', '', '');
107
+ 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'));
103
108
  });