kokopu-react 3.1.0 → 3.2.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 (234) hide show
  1. package/.eslintrc.yml +1 -1
  2. package/CHANGELOG.md +6 -0
  3. package/dist/lib/chessboard/BoardProperties.js.map +1 -1
  4. package/dist/lib/chessboard/Chessboard.css +13 -13
  5. package/dist/lib/chessboard/Chessboard.js.map +1 -1
  6. package/dist/lib/chessboard/ChessboardImpl.js.map +1 -1
  7. package/dist/lib/chessboard/Draggable.js.map +1 -1
  8. package/dist/lib/chessboard/Motion.js.map +1 -1
  9. package/dist/lib/chessboard/colorsets.js.map +1 -1
  10. package/dist/lib/chessboard/piecesets.js.map +1 -1
  11. package/dist/lib/errorbox/ErrorBox.css +18 -18
  12. package/dist/lib/errorbox/ErrorBox.js.map +1 -1
  13. package/dist/lib/errorbox/parsing.js.map +1 -1
  14. package/dist/lib/exception.js.map +1 -1
  15. package/dist/lib/i18n.d.ts +1 -0
  16. package/dist/lib/i18n.js +1 -0
  17. package/dist/lib/i18n.js.map +1 -1
  18. package/dist/lib/icons/AnnotationSymbolShape.css +6 -6
  19. package/dist/lib/icons/AnnotationSymbolShape.js.map +1 -1
  20. package/dist/lib/icons/ArrowMarkerIcon.js.map +1 -1
  21. package/dist/lib/icons/ArrowTip.js.map +1 -1
  22. package/dist/lib/icons/ChessPieceIcon.js.map +1 -1
  23. package/dist/lib/icons/SquareMarkerIcon.js.map +1 -1
  24. package/dist/lib/icons/TextMarkerIcon.js.map +1 -1
  25. package/dist/lib/icons/arrow.css +1 -1
  26. package/dist/lib/index.d.ts +1 -0
  27. package/dist/lib/index.js +1 -0
  28. package/dist/lib/index.js.map +1 -1
  29. package/dist/lib/movetext/Movetext.css +27 -27
  30. package/dist/lib/movetext/Movetext.js.map +1 -1
  31. package/dist/lib/movetext/MovetextImpl.js.map +1 -1
  32. package/dist/lib/movetext/fonts.css +7 -7
  33. package/dist/lib/movetext/htmlFilter.js.map +1 -1
  34. package/dist/lib/movetext/moveFormatter.js.map +1 -1
  35. package/dist/lib/navigationboard/NavigationBoard.d.ts +39 -1
  36. package/dist/lib/navigationboard/NavigationBoard.js +94 -11
  37. package/dist/lib/navigationboard/NavigationBoard.js.map +1 -1
  38. package/dist/lib/navigationboard/NavigationButton.d.ts +54 -0
  39. package/dist/lib/navigationboard/NavigationButton.js +35 -0
  40. package/dist/lib/navigationboard/NavigationButton.js.map +1 -0
  41. package/dist/lib/navigationboard/NavigationField.css +7 -7
  42. package/dist/lib/navigationboard/NavigationField.js.map +1 -1
  43. package/dist/lib/navigationboard/NavigationToolbar.css +16 -13
  44. package/dist/lib/navigationboard/NavigationToolbar.d.ts +3 -10
  45. package/dist/lib/navigationboard/NavigationToolbar.js +31 -82
  46. package/dist/lib/navigationboard/NavigationToolbar.js.map +1 -1
  47. package/dist/lib/navigationboard/iconPaths.d.ts +29 -0
  48. package/dist/lib/navigationboard/iconPaths.js +91 -0
  49. package/dist/lib/navigationboard/iconPaths.js.map +1 -0
  50. package/dist/lib/sanitization.js.map +1 -1
  51. package/dist/lib/types.js.map +1 -1
  52. package/dist/lib/util.js.map +1 -1
  53. package/doc_src/demo/PageChessboardBase.tsx +115 -115
  54. package/doc_src/demo/PageChessboardInteraction.tsx +303 -303
  55. package/doc_src/demo/PageChessboardMove.tsx +173 -173
  56. package/doc_src/demo/PageChessboardSmallScreens.tsx +94 -94
  57. package/doc_src/demo/PageMovetextBase.tsx +180 -180
  58. package/doc_src/demo/PageMovetextInteraction.tsx +123 -123
  59. package/doc_src/demo/PageNavigationBoardBase.tsx +144 -137
  60. package/doc_src/demo/PageNavigationBoardUncontrolledVsControlled.tsx +69 -69
  61. package/doc_src/demo/decs.d.ts +4 -4
  62. package/doc_src/demo/demo.css +12 -12
  63. package/doc_src/demo/util.ts +1 -1
  64. package/doc_src/examples/NavigationBoard.md +1 -1
  65. package/doc_src/theming/LogoRenderer.js +13 -13
  66. package/doc_src/theming/theming.css +5 -5
  67. package/package.json +95 -95
  68. package/scripts/doc.styleguide.config.js +131 -131
  69. package/scripts/doc.tsconfig.json +5 -5
  70. package/scripts/docker-compose.yml +1 -1
  71. package/scripts/test-graphic.tsconfig.json +5 -5
  72. package/scripts/test-graphic.webpack.config.js +57 -57
  73. package/scripts/test-headless.webpack.config.js +29 -29
  74. package/src/chessboard/BoardProperties.ts +68 -68
  75. package/src/chessboard/Chessboard.css +13 -13
  76. package/src/chessboard/Chessboard.tsx +380 -380
  77. package/src/chessboard/ChessboardImpl.tsx +557 -557
  78. package/src/chessboard/Draggable.tsx +185 -185
  79. package/src/chessboard/Motion.tsx +67 -67
  80. package/src/chessboard/colorsets.ts +66 -66
  81. package/src/chessboard/piecesets.ts +84 -84
  82. package/src/decs.d.ts +2 -2
  83. package/src/errorbox/ErrorBox.css +18 -18
  84. package/src/errorbox/ErrorBox.tsx +75 -75
  85. package/src/errorbox/parsing.tsx +95 -95
  86. package/src/exception.ts +17 -17
  87. package/src/i18n.ts +1 -0
  88. package/src/icons/AnnotationSymbolShape.css +6 -6
  89. package/src/icons/AnnotationSymbolShape.tsx +31 -31
  90. package/src/icons/ArrowMarkerIcon.tsx +34 -34
  91. package/src/icons/ArrowTip.tsx +14 -14
  92. package/src/icons/ChessPieceIcon.tsx +45 -45
  93. package/src/icons/SquareMarkerIcon.tsx +20 -20
  94. package/src/icons/TextMarkerIcon.tsx +29 -29
  95. package/src/icons/arrow.css +1 -1
  96. package/src/index.ts +3 -2
  97. package/src/movetext/Movetext.css +27 -27
  98. package/src/movetext/Movetext.tsx +158 -158
  99. package/src/movetext/MovetextImpl.tsx +345 -345
  100. package/src/movetext/fonts.css +7 -7
  101. package/src/movetext/htmlFilter.tsx +129 -129
  102. package/src/movetext/moveFormatter.tsx +37 -37
  103. package/src/navigationboard/NavigationBoard.tsx +297 -178
  104. package/src/navigationboard/NavigationButton.ts +72 -0
  105. package/src/navigationboard/NavigationField.css +7 -7
  106. package/src/navigationboard/NavigationField.tsx +90 -90
  107. package/src/navigationboard/NavigationToolbar.css +16 -13
  108. package/src/navigationboard/NavigationToolbar.tsx +60 -117
  109. package/src/navigationboard/iconPaths.ts +98 -0
  110. package/src/sanitization.ts +17 -17
  111. package/src/types.ts +116 -116
  112. package/src/util.ts +11 -11
  113. package/test/01_types.js +167 -167
  114. package/test/02_chessboard_util.js +114 -114
  115. package/test/03_error_box_graphic.js +16 -16
  116. package/test/04_icons_graphic.js +32 -32
  117. package/test/05_chessboard_graphic.js +60 -60
  118. package/test/06_chessboard_animation.js +36 -36
  119. package/test/07_chessboard_interaction.js +101 -101
  120. package/test/08_chessboard_play_moves.js +62 -62
  121. package/test/09_chessboard_small_screens.js +32 -32
  122. package/test/10_movetext_graphic.js +32 -32
  123. package/test/11_movetext_interaction.js +100 -100
  124. package/test/12_navigation_board_base.js +151 -0
  125. package/test/13_navigation_board_graphic.js +68 -0
  126. package/test/14_navigation_board_autoplay.js +100 -0
  127. package/test/common/graphic.js +106 -97
  128. package/test/graphic_references/12_navigation_board_base/controlled/default.png +0 -0
  129. package/test/graphic_references/{12_navigation_board/controlled/forbidden_navigation_1.png → 12_navigation_board_base/controlled/forbidden_navigation_0.png} +0 -0
  130. package/test/graphic_references/{12_navigation_board/controlled/invalid_node_id.png → 12_navigation_board_base/controlled/forbidden_navigation_1.png} +0 -0
  131. package/test/graphic_references/{12_navigation_board/controlled/forbidden_navigation_0.png → 12_navigation_board_base/controlled/invalid_node_id.png} +0 -0
  132. package/test/graphic_references/12_navigation_board_base/controlled/no_callback_defined_0.png +0 -0
  133. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/controlled/no_callback_defined_1.png +0 -0
  134. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/controlled/overriding_initial_node_id.png +0 -0
  135. package/test/graphic_references/{12_navigation_board/controlled/regular_navigation_1.png → 12_navigation_board_base/controlled/regular_navigation_0.png} +0 -0
  136. package/test/graphic_references/{12_navigation_board/uncontrolled/initial_state_at_specific_id.png → 12_navigation_board_base/controlled/regular_navigation_1.png} +0 -0
  137. package/test/graphic_references/{12_navigation_board/controlled/regular_navigation_3.png → 12_navigation_board_base/controlled/regular_navigation_2.png} +0 -0
  138. package/test/graphic_references/{12_navigation_board/controlled/regular_navigation_0.png → 12_navigation_board_base/controlled/regular_navigation_3.png} +0 -0
  139. package/test/graphic_references/{12_navigation_board/uncontrolled/forbidden_navigation_at_beginning_2.png → 12_navigation_board_base/uncontrolled/forbidden_navigation_at_beginning_0.png} +0 -0
  140. package/test/graphic_references/{12_navigation_board/uncontrolled/forbidden_navigation_at_beginning_0.png → 12_navigation_board_base/uncontrolled/forbidden_navigation_at_beginning_1.png} +0 -0
  141. package/test/graphic_references/{12_navigation_board/uncontrolled/forbidden_navigation_at_beginning_1.png → 12_navigation_board_base/uncontrolled/forbidden_navigation_at_beginning_2.png} +0 -0
  142. package/test/graphic_references/{12_navigation_board/controlled/no_callback_defined_0.png → 12_navigation_board_base/uncontrolled/forbidden_navigation_at_end_0.png} +0 -0
  143. package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_end_1.png +0 -0
  144. package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_end_2.png +0 -0
  145. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/initial_state_at_end.png +0 -0
  146. package/test/graphic_references/12_navigation_board_base/uncontrolled/initial_state_at_specific_id.png +0 -0
  147. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/initial_state_default.png +0 -0
  148. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/initial_state_default_with_game_index.png +0 -0
  149. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/initial_state_on_null-move.png +0 -0
  150. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/navigation_with_keys_0.png +0 -0
  151. package/test/graphic_references/12_navigation_board_base/uncontrolled/navigation_with_keys_1.png +0 -0
  152. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/navigation_with_keys_2.png +0 -0
  153. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/navigation_with_keys_3.png +0 -0
  154. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/navigation_with_keys_4.png +0 -0
  155. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/regular_flipping_0.png +0 -0
  156. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/regular_flipping_1.png +0 -0
  157. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/regular_navigation_0.png +0 -0
  158. package/test/graphic_references/{12_navigation_board/controlled/default.png → 12_navigation_board_base/uncontrolled/regular_navigation_1.png} +0 -0
  159. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/regular_navigation_2.png +0 -0
  160. package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_navigation_3.png +0 -0
  161. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/regular_navigation_4.png +0 -0
  162. package/test/graphic_references/{12_navigation_board → 12_navigation_board_base}/uncontrolled/regular_navigation_5.png +0 -0
  163. package/test/graphic_references/13_navigation_board_graphic/additional_buttons/error_1.png +0 -0
  164. package/test/graphic_references/13_navigation_board_graphic/additional_buttons/error_2.png +0 -0
  165. package/test/graphic_references/13_navigation_board_graphic/additional_buttons/multiple_buttons.png +0 -0
  166. package/test/graphic_references/{12_navigation_board/uncontrolled/regular_navigation_3.png → 13_navigation_board_graphic/additional_buttons/single_button.png} +0 -0
  167. package/test/graphic_references/{12_navigation_board → 13_navigation_board_graphic}/theme/custom_1.png +0 -0
  168. package/test/graphic_references/{12_navigation_board → 13_navigation_board_graphic}/theme/custom_2.png +0 -0
  169. package/test/graphic_references/{12_navigation_board → 13_navigation_board_graphic}/theme/large.png +0 -0
  170. package/test/graphic_references/13_navigation_board_graphic/theme/small.png +0 -0
  171. package/test/graphic_references/14_navigation_board_autoplay/controlled/after_1_move_acknowledging_is-playing_changes.png +0 -0
  172. package/test/graphic_references/14_navigation_board_autoplay/controlled/after_1_move_not_acknowledging_is-playing_changes.png +0 -0
  173. package/test/graphic_references/14_navigation_board_autoplay/controlled/after_2_moves_acknowledging_node_changes.png +0 -0
  174. package/test/graphic_references/14_navigation_board_autoplay/controlled/after_2_moves_not_acknowledging_node_changes.png +0 -0
  175. package/test/graphic_references/{12_navigation_board/uncontrolled/forbidden_navigation_at_end_1.png → 14_navigation_board_autoplay/controlled/after_reaching_the_end.png} +0 -0
  176. package/test/graphic_references/{12_navigation_board/uncontrolled/forbidden_navigation_at_end_2.png → 14_navigation_board_autoplay/controlled/already_at_the_end.png} +0 -0
  177. package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_acknowledging_is-playing_changes.png +0 -0
  178. package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_acknowledging_node_changes.png +0 -0
  179. package/test/graphic_references/{12_navigation_board/uncontrolled/forbidden_navigation_at_end_0.png → 14_navigation_board_autoplay/controlled/initial_state_at_the_end.png} +0 -0
  180. package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_close_to_end.png +0 -0
  181. package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_not_acknowledging_is-playing_changes.png +0 -0
  182. package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_not_acknowledging_node_changes.png +0 -0
  183. package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_2_moves_from_beginning_after_stop.png +0 -0
  184. package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_2_moves_from_beginning_before_stop.png +0 -0
  185. package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_reaching_the_end_after_stop.png +0 -0
  186. package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_reaching_the_end_before_stop.png +0 -0
  187. package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/initial_state_close_to_end.png +0 -0
  188. package/test/graphic_references/{12_navigation_board/uncontrolled/navigation_with_keys_1.png → 14_navigation_board_autoplay/uncontrolled/initial_state_default.png} +0 -0
  189. package/test/graphic_test_app/03_error_box_graphic/base.tsx +14 -14
  190. package/test/graphic_test_app/03_error_box_graphic/localization.tsx +1 -1
  191. package/test/graphic_test_app/04_icons_graphic/chess_piece.tsx +7 -7
  192. package/test/graphic_test_app/04_icons_graphic/marker.tsx +15 -15
  193. package/test/graphic_test_app/05_chessboard_graphic/annotations.tsx +7 -7
  194. package/test/graphic_test_app/05_chessboard_graphic/base.tsx +6 -6
  195. package/test/graphic_test_app/05_chessboard_graphic/chess_variants.tsx +7 -7
  196. package/test/graphic_test_app/05_chessboard_graphic/flipped.tsx +5 -5
  197. package/test/graphic_test_app/05_chessboard_graphic/move.tsx +12 -12
  198. package/test/graphic_test_app/05_chessboard_graphic/theme.tsx +12 -12
  199. package/test/graphic_test_app/06_chessboard_animation/base_1.tsx +6 -6
  200. package/test/graphic_test_app/06_chessboard_animation/base_2.tsx +6 -6
  201. package/test/graphic_test_app/06_chessboard_animation/base_3.tsx +6 -6
  202. package/test/graphic_test_app/06_chessboard_animation/on_redraw.tsx +16 -16
  203. package/test/graphic_test_app/07_chessboard_interaction/click_squares.tsx +5 -5
  204. package/test/graphic_test_app/07_chessboard_interaction/edit_arrows.tsx +4 -4
  205. package/test/graphic_test_app/07_chessboard_interaction/error.tsx +2 -2
  206. package/test/graphic_test_app/07_chessboard_interaction/move_pieces.tsx +5 -5
  207. package/test/graphic_test_app/08_chessboard_play_moves/base.tsx +8 -8
  208. package/test/graphic_test_app/08_chessboard_play_moves/promotions.tsx +4 -4
  209. package/test/graphic_test_app/09_chessboard_small_screens/base.tsx +9 -9
  210. package/test/graphic_test_app/09_chessboard_small_screens/top_bottom_components.tsx +9 -9
  211. package/test/graphic_test_app/10_movetext_graphic/base.tsx +4 -4
  212. package/test/graphic_test_app/10_movetext_graphic/error.tsx +6 -6
  213. package/test/graphic_test_app/10_movetext_graphic/format_move.tsx +1 -1
  214. package/test/graphic_test_app/10_movetext_graphic/html.tsx +5 -5
  215. package/test/graphic_test_app/10_movetext_graphic/options.tsx +10 -10
  216. package/test/graphic_test_app/11_movetext_interaction/error.tsx +1 -1
  217. package/test/graphic_test_app/11_movetext_interaction/select_moves.tsx +11 -11
  218. package/test/graphic_test_app/{12_navigation_board → 12_navigation_board_base}/controlled.tsx +5 -5
  219. package/test/graphic_test_app/{12_navigation_board → 12_navigation_board_base}/uncontrolled.tsx +7 -7
  220. package/test/graphic_test_app/13_navigation_board_graphic/additional_buttons.tsx +49 -0
  221. package/test/graphic_test_app/{12_navigation_board → 13_navigation_board_graphic}/error.tsx +2 -2
  222. package/test/graphic_test_app/{12_navigation_board → 13_navigation_board_graphic}/theme.tsx +4 -4
  223. package/test/graphic_test_app/14_navigation_board_autoplay/controlled.tsx +73 -0
  224. package/test/graphic_test_app/14_navigation_board_autoplay/uncontrolled.tsx +34 -0
  225. package/test/graphic_test_app/common/decs.d.ts +2 -2
  226. package/test/graphic_test_app/common/test_app.css +15 -15
  227. package/test/graphic_test_app/common/test_app.tsx +48 -48
  228. package/tsconfig.json +13 -13
  229. package/test/12_navigation_board.js +0 -168
  230. package/test/graphic_references/12_navigation_board/controlled/regular_navigation_2.png +0 -0
  231. package/test/graphic_references/12_navigation_board/theme/small.png +0 -0
  232. package/test/graphic_references/12_navigation_board/uncontrolled/regular_navigation_1.png +0 -0
  233. /package/test/graphic_references/{12_navigation_board → 13_navigation_board_graphic}/error/pgn_parsing_error.png +0 -0
  234. /package/test/graphic_references/{12_navigation_board → 13_navigation_board_graphic}/error/wrong_game_type.png +0 -0
@@ -23,14 +23,14 @@
23
23
 
24
24
 
25
25
  @font-face {
26
- font-family: 'Chess Alpha';
27
- src:
28
- url('./fonts/chessalpha.woff2') format('woff2'),
29
- url('./fonts/chessalpha.woff') format('woff');
30
- font-weight: normal;
31
- font-style: normal;
26
+ font-family: 'Chess Alpha';
27
+ src:
28
+ url('./fonts/chessalpha.woff2') format('woff2'),
29
+ url('./fonts/chessalpha.woff') format('woff');
30
+ font-weight: normal;
31
+ font-style: normal;
32
32
  }
33
33
 
34
34
  .kokopu-font-alpha {
35
- font-family: 'Chess Alpha', sans-serif;
35
+ font-family: 'Chess Alpha', sans-serif;
36
36
  }
@@ -45,48 +45,48 @@ type ChildNode = ReturnType<typeof htmlparser2.parseDocument>['children'][0];
45
45
  */
46
46
  export function htmlFilter(type: 'header' | 'comment'): (text: string) => React.ReactNode {
47
47
 
48
- let allowedTags = [
49
- 'span', // general purpose
50
- 'a', // links
51
- 'b', 'strong', 'i', 'em', // bold, italic
52
- 'del', 'ins', 's', 'u', // underline, strikethrough
53
- 'sub', 'sup', // subscript, superscript
54
- 'abbr', // acronym (typically associated to a title=".." tooltip)
55
- 'q', 'cite', // quotation and title of a work
56
- 'mark', // highlighted text
57
- 'small', // smaller text
58
- ];
59
- const allowedAttributes: Record<string, string[]> = {
60
- '*': [ 'class', 'id', 'title' ],
61
- 'a': [ 'href', 'target' ],
62
- };
63
-
64
- if (type === 'comment') {
65
- allowedTags = allowedTags.concat([
66
- 'div', // general purpose
67
- 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', // headings
68
- 'p', 'br', // paragraph and line break
69
- 'blockquote', // long quotation
70
- 'img', // image
71
- 'pre', // preformatted text
72
- 'ul', 'ol', 'li', // lists
73
- ]);
74
- Object.assign(allowedAttributes, {
75
- 'img': [ 'alt', 'src', 'height', 'width' ],
76
- });
77
- }
78
-
79
- const sanitizer = new HtmlSanitizer({
80
- allowedTags: allowedTags,
81
- allowedAttributes: allowedAttributes,
82
- });
83
- return text => sanitizer.parse(text);
48
+ let allowedTags = [
49
+ 'span', // general purpose
50
+ 'a', // links
51
+ 'b', 'strong', 'i', 'em', // bold, italic
52
+ 'del', 'ins', 's', 'u', // underline, strikethrough
53
+ 'sub', 'sup', // subscript, superscript
54
+ 'abbr', // acronym (typically associated to a title=".." tooltip)
55
+ 'q', 'cite', // quotation and title of a work
56
+ 'mark', // highlighted text
57
+ 'small', // smaller text
58
+ ];
59
+ const allowedAttributes: Record<string, string[]> = {
60
+ '*': [ 'class', 'id', 'title' ],
61
+ 'a': [ 'href', 'target' ],
62
+ };
63
+
64
+ if (type === 'comment') {
65
+ allowedTags = allowedTags.concat([
66
+ 'div', // general purpose
67
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', // headings
68
+ 'p', 'br', // paragraph and line break
69
+ 'blockquote', // long quotation
70
+ 'img', // image
71
+ 'pre', // preformatted text
72
+ 'ul', 'ol', 'li', // lists
73
+ ]);
74
+ Object.assign(allowedAttributes, {
75
+ 'img': [ 'alt', 'src', 'height', 'width' ],
76
+ });
77
+ }
78
+
79
+ const sanitizer = new HtmlSanitizer({
80
+ allowedTags: allowedTags,
81
+ allowedAttributes: allowedAttributes,
82
+ });
83
+ return text => sanitizer.parse(text);
84
84
  }
85
85
 
86
86
 
87
87
  interface HtmlSanitizerProps {
88
- allowedTags?: string[];
89
- allowedAttributes?: Record<string, string[]>;
88
+ allowedTags?: string[];
89
+ allowedAttributes?: Record<string, string[]>;
90
90
  }
91
91
 
92
92
 
@@ -95,96 +95,96 @@ interface HtmlSanitizerProps {
95
95
  */
96
96
  class HtmlSanitizer {
97
97
 
98
- #allowedTags: Set<string>;
99
- #allowedAttributes: Map<string, Set<string>>;
100
- #keyCounter = 0;
101
-
102
- constructor({ allowedTags, allowedAttributes }: HtmlSanitizerProps) {
103
- this.#allowedTags = allowedTags ? new Set(allowedTags) : new Set();
104
- this.#allowedAttributes = allowedAttributes ? new Map(Object.entries(allowedAttributes).map(([k, v]) => [k, new Set(v)])) : new Map();
105
- }
106
-
107
- /**
108
- * @param text - HTML string to be parsed.
109
- * @returns React object corresponding to the given HTML string. Can also be a fragment, or just a simple string if the given HTML string
110
- * does not contain any HTML tag.
111
- */
112
- parse(text: string): React.ReactNode {
113
- const dom = htmlparser2.parseDocument(text);
114
-
115
- // Ensure that the returned object is a non-empty node type.
116
- if (dom.type !== 'root') {
117
- return undefined;
118
- }
119
-
120
- // Process the children of the root node.
121
- const result: React.ReactNode[] = [];
122
- dom.children.forEach(child => {
123
- const childElement = this.processNode(child);
124
- if (childElement) {
125
- result.push(childElement);
126
- }
127
- });
128
-
129
- // Return the result.
130
- if (result.length === 0) {
131
- return undefined;
132
- }
133
- else if (result.length === 1) {
134
- return result[0];
135
- }
136
- else {
137
- return <React.Fragment key={this.allocateKey()}>{result}</React.Fragment>;
138
- }
139
- }
140
-
141
- private processNode(node: ChildNode): React.ReactNode {
142
- if (node.type === 'text') {
143
- return node.data;
144
- }
145
- else if (node.type === 'tag') {
146
- const children = NO_CHILDREN_TAGS.has(node.name) ? undefined : node.children.map(child => this.processNode(child));
147
- if (this.#allowedTags.has(node.name)) {
148
- const attributes = this.filterAttributes(node.name, node.attribs);
149
- attributes['key'] = this.allocateKey();
150
- return React.createElement(node.name, attributes, children);
151
- }
152
- else {
153
- return children ? <React.Fragment key={this.allocateKey()}>{children}</React.Fragment> : undefined;
154
- }
155
- }
156
- else {
157
- return undefined;
158
- }
159
- }
160
-
161
- private filterAttributes(nodeName: string, attributes: Record<string, string>) {
162
- const result: Record<string, string> = {};
163
- for (const [ attribute, value ] of Object.entries(attributes)) {
164
- if (this.isAttributeAllowed(nodeName, attribute)) {
165
- result[attribute === 'class' ? 'className' : attribute] = value;
166
- }
167
- }
168
- return result;
169
- }
170
-
171
- private isAttributeAllowed(nodeName: string, attribute: string) {
172
- if (attribute === 'key' || attribute === 'ref' || attribute === 'className') { // Those attributes are always forbidden.
173
- return false;
174
- }
175
- const allowedAttributesForCurrent = this.#allowedAttributes.get(nodeName);
176
- if (allowedAttributesForCurrent && allowedAttributesForCurrent.has(attribute)) {
177
- return true;
178
- }
179
- const allowedAttributesForAll = this.#allowedAttributes.get('*');
180
- if (allowedAttributesForAll && allowedAttributesForAll.has(attribute)) {
181
- return true;
182
- }
183
- return false;
184
- }
185
-
186
- private allocateKey() {
187
- return 'auto-' + (this.#keyCounter++);
188
- }
98
+ #allowedTags: Set<string>;
99
+ #allowedAttributes: Map<string, Set<string>>;
100
+ #keyCounter = 0;
101
+
102
+ constructor({ allowedTags, allowedAttributes }: HtmlSanitizerProps) {
103
+ this.#allowedTags = allowedTags ? new Set(allowedTags) : new Set();
104
+ this.#allowedAttributes = allowedAttributes ? new Map(Object.entries(allowedAttributes).map(([k, v]) => [k, new Set(v)])) : new Map();
105
+ }
106
+
107
+ /**
108
+ * @param text - HTML string to be parsed.
109
+ * @returns React object corresponding to the given HTML string. Can also be a fragment, or just a simple string if the given HTML string
110
+ * does not contain any HTML tag.
111
+ */
112
+ parse(text: string): React.ReactNode {
113
+ const dom = htmlparser2.parseDocument(text);
114
+
115
+ // Ensure that the returned object is a non-empty node type.
116
+ if (dom.type !== 'root') {
117
+ return undefined;
118
+ }
119
+
120
+ // Process the children of the root node.
121
+ const result: React.ReactNode[] = [];
122
+ dom.children.forEach(child => {
123
+ const childElement = this.processNode(child);
124
+ if (childElement) {
125
+ result.push(childElement);
126
+ }
127
+ });
128
+
129
+ // Return the result.
130
+ if (result.length === 0) {
131
+ return undefined;
132
+ }
133
+ else if (result.length === 1) {
134
+ return result[0];
135
+ }
136
+ else {
137
+ return <React.Fragment key={this.allocateKey()}>{result}</React.Fragment>;
138
+ }
139
+ }
140
+
141
+ private processNode(node: ChildNode): React.ReactNode {
142
+ if (node.type === 'text') {
143
+ return node.data;
144
+ }
145
+ else if (node.type === 'tag') {
146
+ const children = NO_CHILDREN_TAGS.has(node.name) ? undefined : node.children.map(child => this.processNode(child));
147
+ if (this.#allowedTags.has(node.name)) {
148
+ const attributes = this.filterAttributes(node.name, node.attribs);
149
+ attributes['key'] = this.allocateKey();
150
+ return React.createElement(node.name, attributes, children);
151
+ }
152
+ else {
153
+ return children ? <React.Fragment key={this.allocateKey()}>{children}</React.Fragment> : undefined;
154
+ }
155
+ }
156
+ else {
157
+ return undefined;
158
+ }
159
+ }
160
+
161
+ private filterAttributes(nodeName: string, attributes: Record<string, string>) {
162
+ const result: Record<string, string> = {};
163
+ for (const [ attribute, value ] of Object.entries(attributes)) {
164
+ if (this.isAttributeAllowed(nodeName, attribute)) {
165
+ result[attribute === 'class' ? 'className' : attribute] = value;
166
+ }
167
+ }
168
+ return result;
169
+ }
170
+
171
+ private isAttributeAllowed(nodeName: string, attribute: string) {
172
+ if (attribute === 'key' || attribute === 'ref' || attribute === 'className') { // Those attributes are always forbidden.
173
+ return false;
174
+ }
175
+ const allowedAttributesForCurrent = this.#allowedAttributes.get(nodeName);
176
+ if (allowedAttributesForCurrent && allowedAttributesForCurrent.has(attribute)) {
177
+ return true;
178
+ }
179
+ const allowedAttributesForAll = this.#allowedAttributes.get('*');
180
+ if (allowedAttributesForAll && allowedAttributesForAll.has(attribute)) {
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+
186
+ private allocateKey() {
187
+ return 'auto-' + (this.#keyCounter++);
188
+ }
189
189
 
190
190
  }
@@ -38,8 +38,8 @@ import './fonts.css';
38
38
  * @param notation - SAN notation.
39
39
  */
40
40
  export function formatMove(pieceSymbols: 'native' | 'localized' | 'figurines' | PieceSymbolMapping, notation: string): React.ReactNode {
41
- const formatter = moveFormatter(pieceSymbols);
42
- return formatter(notation);
41
+ const formatter = moveFormatter(pieceSymbols);
42
+ return formatter(notation);
43
43
  }
44
44
 
45
45
 
@@ -53,22 +53,22 @@ export function formatMove(pieceSymbols: 'native' | 'localized' | 'figurines' |
53
53
  * - {@link PieceSymbolMapping}: use the given custom set of chess piece symbols.
54
54
  */
55
55
  export function moveFormatter(pieceSymbols: 'native' | 'localized' | 'figurines' | PieceSymbolMapping): (notation: string) => React.ReactNode {
56
- if (pieceSymbols === 'native') {
57
- return notation => notation;
58
- }
59
- else if (pieceSymbols === 'localized') {
60
- const mapping = i18n.PIECE_SYMBOLS;
61
- return notation => pieceMappingNotation(mapping, notation);
62
- }
63
- else if (pieceSymbols === 'figurines') {
64
- return notation => figurineNotation('alpha', notation);
65
- }
66
- else if (isPieceSymbolMapping(pieceSymbols)) {
67
- return notation => pieceMappingNotation(pieceSymbols, notation);
68
- }
69
- else {
70
- throw new IllegalArgument('moveFormatter', 'pieceSymbols');
71
- }
56
+ if (pieceSymbols === 'native') {
57
+ return notation => notation;
58
+ }
59
+ else if (pieceSymbols === 'localized') {
60
+ const mapping = i18n.PIECE_SYMBOLS;
61
+ return notation => pieceMappingNotation(mapping, notation);
62
+ }
63
+ else if (pieceSymbols === 'figurines') {
64
+ return notation => figurineNotation('alpha', notation);
65
+ }
66
+ else if (isPieceSymbolMapping(pieceSymbols)) {
67
+ return notation => pieceMappingNotation(pieceSymbols, notation);
68
+ }
69
+ else {
70
+ throw new IllegalArgument('moveFormatter', 'pieceSymbols');
71
+ }
72
72
  }
73
73
 
74
74
 
@@ -76,7 +76,7 @@ export function moveFormatter(pieceSymbols: 'native' | 'localized' | 'figurines'
76
76
  * Replace the native piece symbols by those defined by the given {@link PieceSymbolMapping}.
77
77
  */
78
78
  function pieceMappingNotation(mapping: PieceSymbolMapping, text: string) {
79
- return text.replace(/[KQRBNP]/g, match => mapping[match as keyof PieceSymbolMapping]);
79
+ return text.replace(/[KQRBNP]/g, match => mapping[match as keyof PieceSymbolMapping]);
80
80
  }
81
81
 
82
82
 
@@ -85,22 +85,22 @@ function pieceMappingNotation(mapping: PieceSymbolMapping, text: string) {
85
85
  * React objects represented with the given chess font.
86
86
  */
87
87
  function figurineNotation(fontName: string, text: string): React.ReactNode {
88
- const result: React.ReactNode[] = [];
89
- let beginOfText = 0;
90
- let pieceSymbolIndex = 0;
91
- for (let pos = 0; pos < text.length; ++pos) {
92
- const currentChar = text.charAt(pos);
93
- if (currentChar === 'K' || currentChar === 'Q' || currentChar === 'R' || currentChar === 'B' || currentChar === 'N' || currentChar === 'P') {
94
- if (pos > beginOfText) {
95
- result.push(text.substring(beginOfText, pos));
96
- }
97
- beginOfText = pos + 1;
98
- const key = 'symbol-' + (pieceSymbolIndex++);
99
- result.push(<span className={'kokopu-font-' + fontName} key={key}>{currentChar}</span>);
100
- }
101
- }
102
- if (beginOfText < text.length) {
103
- result.push(text.substring(beginOfText));
104
- }
105
- return <>{result}</>;
88
+ const result: React.ReactNode[] = [];
89
+ let beginOfText = 0;
90
+ let pieceSymbolIndex = 0;
91
+ for (let pos = 0; pos < text.length; ++pos) {
92
+ const currentChar = text.charAt(pos);
93
+ if (currentChar === 'K' || currentChar === 'Q' || currentChar === 'R' || currentChar === 'B' || currentChar === 'N' || currentChar === 'P') {
94
+ if (pos > beginOfText) {
95
+ result.push(text.substring(beginOfText, pos));
96
+ }
97
+ beginOfText = pos + 1;
98
+ const key = 'symbol-' + (pieceSymbolIndex++);
99
+ result.push(<span className={'kokopu-font-' + fontName} key={key}>{currentChar}</span>);
100
+ }
101
+ }
102
+ if (beginOfText < text.length) {
103
+ result.push(text.substring(beginOfText));
104
+ }
105
+ return <>{result}</>;
106
106
  }