@mirasen/chessboard 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +96 -0
  4. package/assets/pieces/chessnut/ATTRIBUTION.md +13 -0
  5. package/assets/pieces/chessnut/LICENSE.txt +202 -0
  6. package/assets/pieces/chessnut/bB.svg +58 -0
  7. package/assets/pieces/chessnut/bK.svg +51 -0
  8. package/assets/pieces/chessnut/bN.svg +19 -0
  9. package/assets/pieces/chessnut/bP.svg +17 -0
  10. package/assets/pieces/chessnut/bQ.svg +97 -0
  11. package/assets/pieces/chessnut/bR.svg +34 -0
  12. package/assets/pieces/chessnut/wB.svg +61 -0
  13. package/assets/pieces/chessnut/wK.svg +71 -0
  14. package/assets/pieces/chessnut/wN.svg +19 -0
  15. package/assets/pieces/chessnut/wP.svg +17 -0
  16. package/assets/pieces/chessnut/wQ.svg +40 -0
  17. package/assets/pieces/chessnut/wR.svg +38 -0
  18. package/dist/animation/planner.d.ts +6 -0
  19. package/dist/animation/planner.js +128 -0
  20. package/dist/animation/render/fade.d.ts +7 -0
  21. package/dist/animation/render/fade.js +24 -0
  22. package/dist/animation/render/move.d.ts +7 -0
  23. package/dist/animation/render/move.js +28 -0
  24. package/dist/animation/render/plan.d.ts +14 -0
  25. package/dist/animation/render/plan.js +69 -0
  26. package/dist/animation/render/static.d.ts +7 -0
  27. package/dist/animation/render/static.js +21 -0
  28. package/dist/animation/render/types.d.ts +21 -0
  29. package/dist/animation/render/types.js +1 -0
  30. package/dist/animation/types.d.ts +46 -0
  31. package/dist/animation/types.js +6 -0
  32. package/dist/extensions/animation/factory.d.ts +3 -0
  33. package/dist/extensions/animation/factory.js +88 -0
  34. package/dist/extensions/animation/types.d.ts +11 -0
  35. package/dist/extensions/animation/types.js +1 -0
  36. package/dist/extensions/factory/main.d.ts +2 -0
  37. package/dist/extensions/factory/main.js +101 -0
  38. package/dist/extensions/factory/runtime.d.ts +5 -0
  39. package/dist/extensions/factory/runtime.js +43 -0
  40. package/dist/extensions/first-party/active-target/factory.d.ts +2 -0
  41. package/dist/extensions/first-party/active-target/factory.js +109 -0
  42. package/dist/extensions/first-party/active-target/types.d.ts +25 -0
  43. package/dist/extensions/first-party/active-target/types.js +15 -0
  44. package/dist/extensions/first-party/board-events/factory.d.ts +2 -0
  45. package/dist/extensions/first-party/board-events/factory.js +65 -0
  46. package/dist/extensions/first-party/board-events/types.d.ts +27 -0
  47. package/dist/extensions/first-party/board-events/types.js +2 -0
  48. package/dist/extensions/first-party/common/helpers.d.ts +8 -0
  49. package/dist/extensions/first-party/common/helpers.js +33 -0
  50. package/dist/extensions/first-party/common/types.d.ts +10 -0
  51. package/dist/extensions/first-party/common/types.js +1 -0
  52. package/dist/extensions/first-party/last-move/factory.d.ts +2 -0
  53. package/dist/extensions/first-party/last-move/factory.js +106 -0
  54. package/dist/extensions/first-party/last-move/types.d.ts +19 -0
  55. package/dist/extensions/first-party/last-move/types.js +6 -0
  56. package/dist/extensions/first-party/legal-moves/factory.d.ts +2 -0
  57. package/dist/extensions/first-party/legal-moves/factory.js +101 -0
  58. package/dist/extensions/first-party/legal-moves/types.d.ts +29 -0
  59. package/dist/extensions/first-party/legal-moves/types.js +19 -0
  60. package/dist/extensions/first-party/main-renderer/animation/factory.d.ts +4 -0
  61. package/dist/extensions/first-party/main-renderer/animation/factory.js +35 -0
  62. package/dist/extensions/first-party/main-renderer/animation/render.d.ts +7 -0
  63. package/dist/extensions/first-party/main-renderer/animation/render.js +46 -0
  64. package/dist/extensions/first-party/main-renderer/animation/types.d.ts +24 -0
  65. package/dist/extensions/first-party/main-renderer/animation/types.js +1 -0
  66. package/dist/extensions/first-party/main-renderer/animation/update.d.ts +3 -0
  67. package/dist/extensions/first-party/main-renderer/animation/update.js +40 -0
  68. package/dist/extensions/first-party/main-renderer/board/factory.d.ts +3 -0
  69. package/dist/extensions/first-party/main-renderer/board/factory.js +16 -0
  70. package/dist/extensions/first-party/main-renderer/board/render.d.ts +3 -0
  71. package/dist/extensions/first-party/main-renderer/board/render.js +24 -0
  72. package/dist/extensions/first-party/main-renderer/board/types.d.ts +10 -0
  73. package/dist/extensions/first-party/main-renderer/board/types.js +1 -0
  74. package/dist/extensions/first-party/main-renderer/board/update.d.ts +3 -0
  75. package/dist/extensions/first-party/main-renderer/board/update.js +27 -0
  76. package/dist/extensions/first-party/main-renderer/coordinates/factory.d.ts +3 -0
  77. package/dist/extensions/first-party/main-renderer/coordinates/factory.js +9 -0
  78. package/dist/extensions/first-party/main-renderer/coordinates/render.d.ts +3 -0
  79. package/dist/extensions/first-party/main-renderer/coordinates/render.js +60 -0
  80. package/dist/extensions/first-party/main-renderer/coordinates/types.d.ts +8 -0
  81. package/dist/extensions/first-party/main-renderer/coordinates/types.js +1 -0
  82. package/dist/extensions/first-party/main-renderer/drag/factory.d.ts +4 -0
  83. package/dist/extensions/first-party/main-renderer/drag/factory.js +23 -0
  84. package/dist/extensions/first-party/main-renderer/drag/render.d.ts +3 -0
  85. package/dist/extensions/first-party/main-renderer/drag/render.js +27 -0
  86. package/dist/extensions/first-party/main-renderer/drag/types.d.ts +16 -0
  87. package/dist/extensions/first-party/main-renderer/drag/types.js +1 -0
  88. package/dist/extensions/first-party/main-renderer/drag/update.d.ts +3 -0
  89. package/dist/extensions/first-party/main-renderer/drag/update.js +23 -0
  90. package/dist/extensions/first-party/main-renderer/factory.d.ts +2 -0
  91. package/dist/extensions/first-party/main-renderer/factory.js +95 -0
  92. package/dist/extensions/first-party/main-renderer/normalize.d.ts +4 -0
  93. package/dist/extensions/first-party/main-renderer/normalize.js +27 -0
  94. package/dist/extensions/first-party/main-renderer/pieces/factory.d.ts +3 -0
  95. package/dist/extensions/first-party/main-renderer/pieces/factory.js +27 -0
  96. package/dist/extensions/first-party/main-renderer/pieces/render.d.ts +3 -0
  97. package/dist/extensions/first-party/main-renderer/pieces/render.js +45 -0
  98. package/dist/extensions/first-party/main-renderer/pieces/suppress.d.ts +5 -0
  99. package/dist/extensions/first-party/main-renderer/pieces/suppress.js +9 -0
  100. package/dist/extensions/first-party/main-renderer/pieces/types.d.ts +20 -0
  101. package/dist/extensions/first-party/main-renderer/pieces/types.js +1 -0
  102. package/dist/extensions/first-party/main-renderer/pieces/update.d.ts +6 -0
  103. package/dist/extensions/first-party/main-renderer/pieces/update.js +31 -0
  104. package/dist/extensions/first-party/main-renderer/types/extension.d.ts +15 -0
  105. package/dist/extensions/first-party/main-renderer/types/extension.js +10 -0
  106. package/dist/extensions/first-party/main-renderer/types/input.d.ts +4 -0
  107. package/dist/extensions/first-party/main-renderer/types/input.js +1 -0
  108. package/dist/extensions/first-party/main-renderer/types/instance.d.ts +16 -0
  109. package/dist/extensions/first-party/main-renderer/types/instance.js +1 -0
  110. package/dist/extensions/first-party/main-renderer/types/internal.d.ts +17 -0
  111. package/dist/extensions/first-party/main-renderer/types/internal.js +30 -0
  112. package/dist/extensions/first-party/main-renderer/types/template.d.ts +5 -0
  113. package/dist/extensions/first-party/main-renderer/types/template.js +1 -0
  114. package/dist/extensions/first-party/selected-square/factory.d.ts +2 -0
  115. package/dist/extensions/first-party/selected-square/factory.js +88 -0
  116. package/dist/extensions/first-party/selected-square/types.d.ts +18 -0
  117. package/dist/extensions/first-party/selected-square/types.js +6 -0
  118. package/dist/extensions/index.d.ts +8 -0
  119. package/dist/extensions/index.js +6 -0
  120. package/dist/extensions/invalidation/factory.d.ts +2 -0
  121. package/dist/extensions/invalidation/factory.js +22 -0
  122. package/dist/extensions/invalidation/types.d.ts +11 -0
  123. package/dist/extensions/invalidation/types.js +1 -0
  124. package/dist/extensions/types/basic/animation.d.ts +28 -0
  125. package/dist/extensions/types/basic/animation.js +6 -0
  126. package/dist/extensions/types/basic/events.d.ts +34 -0
  127. package/dist/extensions/types/basic/events.js +7 -0
  128. package/dist/extensions/types/basic/mount.d.ts +7 -0
  129. package/dist/extensions/types/basic/mount.js +14 -0
  130. package/dist/extensions/types/basic/render.d.ts +9 -0
  131. package/dist/extensions/types/basic/render.js +1 -0
  132. package/dist/extensions/types/basic/transient-visuals.d.ts +10 -0
  133. package/dist/extensions/types/basic/transient-visuals.js +1 -0
  134. package/dist/extensions/types/basic/update.d.ts +16 -0
  135. package/dist/extensions/types/basic/update.js +11 -0
  136. package/dist/extensions/types/context/animation.d.ts +31 -0
  137. package/dist/extensions/types/context/animation.js +9 -0
  138. package/dist/extensions/types/context/render.d.ts +6 -0
  139. package/dist/extensions/types/context/render.js +1 -0
  140. package/dist/extensions/types/context/transient-visuals.d.ts +7 -0
  141. package/dist/extensions/types/context/transient-visuals.js +1 -0
  142. package/dist/extensions/types/context/ui-move.d.ts +16 -0
  143. package/dist/extensions/types/context/ui-move.js +1 -0
  144. package/dist/extensions/types/context/update.d.ts +25 -0
  145. package/dist/extensions/types/context/update.js +10 -0
  146. package/dist/extensions/types/extension.d.ts +40 -0
  147. package/dist/extensions/types/extension.js +1 -0
  148. package/dist/extensions/types/main.d.ts +44 -0
  149. package/dist/extensions/types/main.js +1 -0
  150. package/dist/extensions/types/surface/commands.d.ts +26 -0
  151. package/dist/extensions/types/surface/commands.js +1 -0
  152. package/dist/extensions/types/surface/events.d.ts +5 -0
  153. package/dist/extensions/types/surface/events.js +1 -0
  154. package/dist/extensions/types/surface/main.d.ts +10 -0
  155. package/dist/extensions/types/surface/main.js +1 -0
  156. package/dist/extensions/types/surface/transient-visuals.d.ts +4 -0
  157. package/dist/extensions/types/surface/transient-visuals.js +1 -0
  158. package/dist/extensions/types/wrapper.d.ts +26 -0
  159. package/dist/extensions/types/wrapper.js +11 -0
  160. package/dist/extensions/update.d.ts +4 -0
  161. package/dist/extensions/update.js +29 -0
  162. package/dist/helpers/util.d.ts +1 -0
  163. package/dist/helpers/util.js +9 -0
  164. package/dist/index.d.ts +4 -0
  165. package/dist/index.js +1 -0
  166. package/dist/layout/factory.d.ts +2 -0
  167. package/dist/layout/factory.js +33 -0
  168. package/dist/layout/geometry/factory.d.ts +12 -0
  169. package/dist/layout/geometry/factory.js +33 -0
  170. package/dist/layout/geometry/types.d.ts +20 -0
  171. package/dist/layout/geometry/types.js +1 -0
  172. package/dist/layout/helpers.d.ts +4 -0
  173. package/dist/layout/helpers.js +6 -0
  174. package/dist/layout/mutation.d.ts +6 -0
  175. package/dist/layout/mutation.js +1 -0
  176. package/dist/layout/reducers.d.ts +2 -0
  177. package/dist/layout/reducers.js +30 -0
  178. package/dist/layout/types.d.ts +23 -0
  179. package/dist/layout/types.js +1 -0
  180. package/dist/mutation/pipeline.d.ts +2 -0
  181. package/dist/mutation/pipeline.js +36 -0
  182. package/dist/mutation/session.d.ts +3 -0
  183. package/dist/mutation/session.js +66 -0
  184. package/dist/mutation/types.d.ts +26 -0
  185. package/dist/mutation/types.js +1 -0
  186. package/dist/render/factory.d.ts +2 -0
  187. package/dist/render/factory.js +117 -0
  188. package/dist/render/mount.d.ts +3 -0
  189. package/dist/render/mount.js +28 -0
  190. package/dist/render/rendering/animation.d.ts +13 -0
  191. package/dist/render/rendering/animation.js +92 -0
  192. package/dist/render/rendering/helpers.d.ts +3 -0
  193. package/dist/render/rendering/helpers.js +10 -0
  194. package/dist/render/rendering/state.d.ts +4 -0
  195. package/dist/render/rendering/state.js +48 -0
  196. package/dist/render/rendering/visuals.d.ts +3 -0
  197. package/dist/render/rendering/visuals.js +21 -0
  198. package/dist/render/scheduler/scheduler.d.ts +2 -0
  199. package/dist/render/scheduler/scheduler.js +53 -0
  200. package/dist/render/scheduler/types.d.ts +12 -0
  201. package/dist/render/scheduler/types.js +1 -0
  202. package/dist/render/svg/factory.d.ts +4 -0
  203. package/dist/render/svg/factory.js +38 -0
  204. package/dist/render/svg/helpers.d.ts +18 -0
  205. package/dist/render/svg/helpers.js +34 -0
  206. package/dist/render/types.d.ts +42 -0
  207. package/dist/render/types.js +1 -0
  208. package/dist/runtime/factory/helpers.d.ts +6 -0
  209. package/dist/runtime/factory/helpers.js +42 -0
  210. package/dist/runtime/factory/input.d.ts +3 -0
  211. package/dist/runtime/factory/input.js +98 -0
  212. package/dist/runtime/factory/main.d.ts +2 -0
  213. package/dist/runtime/factory/main.js +182 -0
  214. package/dist/runtime/factory/ui-move.d.ts +4 -0
  215. package/dist/runtime/factory/ui-move.js +84 -0
  216. package/dist/runtime/input/adapter/factory.d.ts +2 -0
  217. package/dist/runtime/input/adapter/factory.js +55 -0
  218. package/dist/runtime/input/adapter/helpers.d.ts +5 -0
  219. package/dist/runtime/input/adapter/helpers.js +23 -0
  220. package/dist/runtime/input/adapter/pointer.d.ts +13 -0
  221. package/dist/runtime/input/adapter/pointer.js +97 -0
  222. package/dist/runtime/input/adapter/types.d.ts +16 -0
  223. package/dist/runtime/input/adapter/types.js +1 -0
  224. package/dist/runtime/input/controller/factory.d.ts +2 -0
  225. package/dist/runtime/input/controller/factory.js +32 -0
  226. package/dist/runtime/input/controller/helpers.d.ts +3 -0
  227. package/dist/runtime/input/controller/helpers.js +12 -0
  228. package/dist/runtime/input/controller/pointer.d.ts +7 -0
  229. package/dist/runtime/input/controller/pointer.js +104 -0
  230. package/dist/runtime/input/controller/transient-visuals.d.ts +3 -0
  231. package/dist/runtime/input/controller/transient-visuals.js +12 -0
  232. package/dist/runtime/input/controller/types.d.ts +25 -0
  233. package/dist/runtime/input/controller/types.js +1 -0
  234. package/dist/runtime/layout.d.ts +2 -0
  235. package/dist/runtime/layout.js +10 -0
  236. package/dist/runtime/lifecycle.d.ts +12 -0
  237. package/dist/runtime/lifecycle.js +49 -0
  238. package/dist/runtime/mutation/extension-update.d.ts +2 -0
  239. package/dist/runtime/mutation/extension-update.js +26 -0
  240. package/dist/runtime/mutation/factory.d.ts +2 -0
  241. package/dist/runtime/mutation/factory.js +47 -0
  242. package/dist/runtime/mutation/interaction.d.ts +2 -0
  243. package/dist/runtime/mutation/interaction.js +34 -0
  244. package/dist/runtime/mutation/invalidation.d.ts +0 -0
  245. package/dist/runtime/mutation/invalidation.js +2 -0
  246. package/dist/runtime/mutation/last-move.d.ts +3 -0
  247. package/dist/runtime/mutation/last-move.js +19 -0
  248. package/dist/runtime/mutation/layout.d.ts +2 -0
  249. package/dist/runtime/mutation/layout.js +8 -0
  250. package/dist/runtime/mutation/pipeline.d.ts +22 -0
  251. package/dist/runtime/mutation/pipeline.js +1 -0
  252. package/dist/runtime/mutation/request-render.d.ts +2 -0
  253. package/dist/runtime/mutation/request-render.js +29 -0
  254. package/dist/runtime/mutation/run.d.ts +2 -0
  255. package/dist/runtime/mutation/run.js +3 -0
  256. package/dist/runtime/mutation/types.d.ts +14 -0
  257. package/dist/runtime/mutation/types.js +1 -0
  258. package/dist/runtime/types/main.d.ts +36 -0
  259. package/dist/runtime/types/main.js +1 -0
  260. package/dist/runtime/types/ui-move.d.ts +9 -0
  261. package/dist/runtime/types/ui-move.js +1 -0
  262. package/dist/state/board/check.d.ts +27 -0
  263. package/dist/state/board/check.js +148 -0
  264. package/dist/state/board/coords.d.ts +4 -0
  265. package/dist/state/board/coords.js +9 -0
  266. package/dist/state/board/denormalize.d.ts +11 -0
  267. package/dist/state/board/denormalize.js +77 -0
  268. package/dist/state/board/factory.d.ts +3 -0
  269. package/dist/state/board/factory.js +46 -0
  270. package/dist/state/board/mutation.d.ts +9 -0
  271. package/dist/state/board/mutation.js +1 -0
  272. package/dist/state/board/normalize.d.ts +8 -0
  273. package/dist/state/board/normalize.js +76 -0
  274. package/dist/state/board/piece.d.ts +3 -0
  275. package/dist/state/board/piece.js +11 -0
  276. package/dist/state/board/position.d.ts +4 -0
  277. package/dist/state/board/position.js +94 -0
  278. package/dist/state/board/reducers.d.ts +8 -0
  279. package/dist/state/board/reducers.js +80 -0
  280. package/dist/state/board/types/input.d.ts +35 -0
  281. package/dist/state/board/types/input.js +1 -0
  282. package/dist/state/board/types/internal.d.ts +54 -0
  283. package/dist/state/board/types/internal.js +17 -0
  284. package/dist/state/board/types/main.d.ts +18 -0
  285. package/dist/state/board/types/main.js +1 -0
  286. package/dist/state/board/types/output.d.ts +5 -0
  287. package/dist/state/board/types/output.js +1 -0
  288. package/dist/state/board/types/template.d.ts +23 -0
  289. package/dist/state/board/types/template.js +1 -0
  290. package/dist/state/change/factory.d.ts +2 -0
  291. package/dist/state/change/factory.js +28 -0
  292. package/dist/state/change/helpers.d.ts +8 -0
  293. package/dist/state/change/helpers.js +86 -0
  294. package/dist/state/change/mutation.d.ts +6 -0
  295. package/dist/state/change/mutation.js +1 -0
  296. package/dist/state/change/reducers.d.ts +5 -0
  297. package/dist/state/change/reducers.js +16 -0
  298. package/dist/state/change/types.d.ts +17 -0
  299. package/dist/state/change/types.js +1 -0
  300. package/dist/state/factory.d.ts +2 -0
  301. package/dist/state/factory.js +24 -0
  302. package/dist/state/interaction/factory.d.ts +2 -0
  303. package/dist/state/interaction/factory.js +83 -0
  304. package/dist/state/interaction/helpers.d.ts +4 -0
  305. package/dist/state/interaction/helpers.js +16 -0
  306. package/dist/state/interaction/movability.d.ts +5 -0
  307. package/dist/state/interaction/movability.js +87 -0
  308. package/dist/state/interaction/mutation.d.ts +11 -0
  309. package/dist/state/interaction/mutation.js +1 -0
  310. package/dist/state/interaction/normalize.d.ts +5 -0
  311. package/dist/state/interaction/normalize.js +50 -0
  312. package/dist/state/interaction/reducers.d.ts +11 -0
  313. package/dist/state/interaction/reducers.js +81 -0
  314. package/dist/state/interaction/types/input.d.ts +18 -0
  315. package/dist/state/interaction/types/input.js +1 -0
  316. package/dist/state/interaction/types/internal.d.ts +35 -0
  317. package/dist/state/interaction/types/internal.js +1 -0
  318. package/dist/state/interaction/types/main.d.ts +33 -0
  319. package/dist/state/interaction/types/main.js +1 -0
  320. package/dist/state/types.d.ts +30 -0
  321. package/dist/state/types.js +1 -0
  322. package/dist/state/view/factory.d.ts +2 -0
  323. package/dist/state/view/factory.js +24 -0
  324. package/dist/state/view/mutation.d.ts +5 -0
  325. package/dist/state/view/mutation.js +1 -0
  326. package/dist/state/view/reducers.d.ts +3 -0
  327. package/dist/state/view/reducers.js +6 -0
  328. package/dist/state/view/types/internal.d.ts +6 -0
  329. package/dist/state/view/types/internal.js +1 -0
  330. package/dist/state/view/types/main.d.ts +12 -0
  331. package/dist/state/view/types/main.js +1 -0
  332. package/dist/wrapper/factory.d.ts +3 -0
  333. package/dist/wrapper/factory.js +61 -0
  334. package/dist/wrapper/types.d.ts +56 -0
  335. package/dist/wrapper/types.js +1 -0
  336. package/package.json +98 -0
@@ -0,0 +1,106 @@
1
+ import assert from '@ktarmyshov/assert';
2
+ import { toMerged } from 'es-toolkit';
3
+ import { createSvgElement, updateElementAttributes } from '../../../render/svg/helpers';
4
+ import { isUpdateContextRenderable } from '../../types/context/update';
5
+ import { extensionCreateInternalBase, extensionDestroy, extensionMount, extensionUnmount } from '../common/helpers';
6
+ import { DEFAULT_CONFIG, EXTENSION_ID, EXTENSION_SLOTS } from './types';
7
+ export function createLastMove(config = {}) {
8
+ const mergedConfig = toMerged(DEFAULT_CONFIG, config);
9
+ return {
10
+ id: EXTENSION_ID,
11
+ slots: EXTENSION_SLOTS,
12
+ createInstance() {
13
+ return createLastMoveInstance(mergedConfig);
14
+ }
15
+ };
16
+ }
17
+ function createLastMoveInternal(config) {
18
+ return {
19
+ ...extensionCreateInternalBase(),
20
+ svgRectFrom: null,
21
+ svgRectTo: null,
22
+ config
23
+ };
24
+ }
25
+ function extensionClean(state) {
26
+ state.svgRectFrom = null;
27
+ state.svgRectTo = null;
28
+ }
29
+ function createLastMoveInstance(config) {
30
+ const internalState = createLastMoveInternal(config);
31
+ return {
32
+ id: EXTENSION_ID,
33
+ mount(env) {
34
+ extensionMount(internalState, env.slotRoots);
35
+ },
36
+ onUpdate(context) {
37
+ const needsRender = context.mutation.hasMutation({
38
+ causes: ['state.change.setLastMove', 'layout.refreshGeometry']
39
+ }) && isUpdateContextRenderable(context);
40
+ if (!needsRender) {
41
+ return; // no-op
42
+ }
43
+ context.invalidation.markDirty(1 /* DirtyLayer.Highlight */);
44
+ },
45
+ render(context) {
46
+ assert(context.invalidation.dirtyLayers !== 0, 'Render should only be called when there are dirty layers');
47
+ const fromSq = context.currentFrame.state.change.lastMove?.from;
48
+ const toSq = context.currentFrame.state.change.lastMove?.to;
49
+ if (fromSq === undefined || fromSq === null || toSq === undefined || toSq === null) {
50
+ if (internalState.svgRectFrom !== null) {
51
+ internalState.svgRectFrom.remove();
52
+ internalState.svgRectFrom = null;
53
+ assert(internalState.svgRectTo, 'svgRectTo should be available if svgRectFrom is available');
54
+ internalState.svgRectTo.remove();
55
+ internalState.svgRectTo = null;
56
+ }
57
+ return;
58
+ }
59
+ const geometry = context.currentFrame.layout.geometry;
60
+ const rFrom = geometry.squareRect(fromSq);
61
+ const rTo = geometry.squareRect(toSq);
62
+ const rectFromAttributes = {
63
+ x: rFrom.x.toString(),
64
+ y: rFrom.y.toString(),
65
+ width: rFrom.size.toString(),
66
+ height: rFrom.size.toString(),
67
+ fill: internalState.config.color,
68
+ 'fill-opacity': internalState.config.opacity.toString(),
69
+ 'shape-rendering': 'crispEdges'
70
+ };
71
+ const rectToAttributes = {
72
+ x: rTo.x.toString(),
73
+ y: rTo.y.toString(),
74
+ width: rTo.size.toString(),
75
+ height: rTo.size.toString(),
76
+ fill: internalState.config.color,
77
+ 'fill-opacity': internalState.config.opacity.toString(),
78
+ 'shape-rendering': 'crispEdges'
79
+ };
80
+ if (internalState.svgRectFrom === null) {
81
+ assert(internalState.slotRoots, 'Slot roots should be available when render is called');
82
+ internalState.svgRectFrom = createSvgElement(internalState.slotRoots.underPieces, 'rect', {
83
+ 'data-chessboard-id': 'last-move-square-from-highlight',
84
+ ...rectFromAttributes
85
+ });
86
+ internalState.svgRectTo = createSvgElement(internalState.slotRoots.underPieces, 'rect', {
87
+ 'data-chessboard-id': 'last-move-square-to-highlight',
88
+ ...rectToAttributes
89
+ });
90
+ }
91
+ else {
92
+ updateElementAttributes(internalState.svgRectFrom, rectFromAttributes);
93
+ assert(internalState.svgRectTo, 'svgRectTo should be available if svgRectFrom is available');
94
+ updateElementAttributes(internalState.svgRectTo, rectToAttributes);
95
+ }
96
+ },
97
+ unmount() {
98
+ extensionUnmount(internalState);
99
+ extensionClean(internalState);
100
+ },
101
+ destroy() {
102
+ extensionDestroy(internalState);
103
+ extensionClean(internalState);
104
+ }
105
+ };
106
+ }
@@ -0,0 +1,19 @@
1
+ import { PartialDeep } from 'type-fest';
2
+ import { ExtensionDefinition, ExtensionInstance } from '../../types/extension';
3
+ import { ExtensionInternal, OpaqueColor } from '../common/types';
4
+ export declare const EXTENSION_SLOTS: readonly ["underPieces"];
5
+ export type ExtensionSlotsType = typeof EXTENSION_SLOTS;
6
+ export declare const EXTENSION_ID: "lastMove";
7
+ export type LastMoveConfig = OpaqueColor;
8
+ export declare const DEFAULT_CONFIG: LastMoveConfig;
9
+ export type LastMoveInitConfig = PartialDeep<LastMoveConfig>;
10
+ export type LastMoveDefinition = ExtensionDefinition<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
11
+ export type LastMoveInstance = ExtensionInstance<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
12
+ export interface LastMoveInstanceInternal extends ExtensionInternal<ExtensionSlotsType> {
13
+ svgRectFrom: SVGRectElement | null;
14
+ svgRectTo: SVGRectElement | null;
15
+ readonly config: LastMoveConfig;
16
+ }
17
+ export declare const enum DirtyLayer {
18
+ Highlight = 1
19
+ }
@@ -0,0 +1,6 @@
1
+ export const EXTENSION_SLOTS = ['underPieces'];
2
+ export const EXTENSION_ID = 'lastMove';
3
+ export const DEFAULT_CONFIG = {
4
+ color: 'rgba(255, 255, 0)',
5
+ opacity: 0.4
6
+ };
@@ -0,0 +1,2 @@
1
+ import { LegalMovesDefinition, LegalMovesInitConfig } from './types';
2
+ export declare function createLegalMoves(config?: LegalMovesInitConfig): LegalMovesDefinition;
@@ -0,0 +1,101 @@
1
+ import assert from '@ktarmyshov/assert';
2
+ import { toMerged } from 'es-toolkit';
3
+ import { clearElementChildren, createSvgElement } from '../../../render/svg/helpers';
4
+ import { isNonEmptyPieceCode } from '../../../state/board/check';
5
+ import { fromPieceCode } from '../../../state/board/piece';
6
+ import { isUpdateContextRenderable } from '../../types/context/update';
7
+ import { extensionCreateInternalBase, extensionDestroy, extensionMount, extensionUnmount } from '../common/helpers';
8
+ import { DEFAULT_CONFIG, EXTENSION_ID, EXTENSION_SLOTS } from './types';
9
+ export function createLegalMoves(config = {}) {
10
+ const mergedConfig = toMerged(DEFAULT_CONFIG, config);
11
+ return {
12
+ id: EXTENSION_ID,
13
+ slots: EXTENSION_SLOTS,
14
+ createInstance() {
15
+ return createLegalMovesInstance(mergedConfig);
16
+ }
17
+ };
18
+ }
19
+ function createLegalMovesInternal(config) {
20
+ return {
21
+ ...extensionCreateInternalBase(),
22
+ svgCircles: [],
23
+ config
24
+ };
25
+ }
26
+ function extensionClean(state) {
27
+ state.svgCircles = [];
28
+ }
29
+ function createLegalMovesInstance(config) {
30
+ const internalState = createLegalMovesInternal(config);
31
+ return {
32
+ id: EXTENSION_ID,
33
+ mount(env) {
34
+ extensionMount(internalState, env.slotRoots);
35
+ },
36
+ onUpdate(context) {
37
+ const needsRender = context.mutation.hasMutation({
38
+ causes: ['layout.refreshGeometry'],
39
+ // we really need almost all: setDrag, updateTarget, clear, clearActive, setMovability, so just take all interaction mutations
40
+ prefixes: ['state.interaction.']
41
+ }) && isUpdateContextRenderable(context);
42
+ if (!needsRender) {
43
+ return; // no-op
44
+ }
45
+ context.invalidation.markDirty(1 /* DirtyLayer.Highlight */);
46
+ },
47
+ render(context) {
48
+ assert(context.invalidation.dirtyLayers !== 0, 'Render should only be called when there are dirty layers');
49
+ assert(internalState.slotRoots, 'Slot roots should be available when render is called');
50
+ clearElementChildren(internalState.slotRoots.overPieces);
51
+ internalState.svgCircles = [];
52
+ const interaction = context.currentFrame.state.interaction;
53
+ const needsRender = interaction.movability.mode === 2 /* MovabilityModeCode.Strict */ &&
54
+ interaction.activeDestinations.size > 0 &&
55
+ interaction.selected !== null;
56
+ if (!needsRender) {
57
+ return; // no-op
58
+ }
59
+ const geometry = context.currentFrame.layout.geometry;
60
+ const commonAttributesEmpty = {
61
+ r: (geometry.squareSize * internalState.config.emptySquare.radiusRatio).toString(),
62
+ fill: internalState.config.emptySquare.color.color,
63
+ 'fill-opacity': internalState.config.emptySquare.color.opacity.toString()
64
+ };
65
+ const commonAttributesCapture = {
66
+ r: (geometry.squareSize * internalState.config.captureTarget.radiusRatio).toString(),
67
+ stroke: internalState.config.captureTarget.color.color,
68
+ 'stroke-opacity': internalState.config.captureTarget.color.opacity.toString(),
69
+ 'stroke-width': (geometry.squareSize * internalState.config.captureTarget.strokeWidthRatio).toString(),
70
+ fill: 'none'
71
+ }; // TODO: Remove, this is just for visual test
72
+ for (const [square, destination] of interaction.activeDestinations) {
73
+ const rect = geometry.squareRect(square);
74
+ const circleX = rect.x + geometry.squareSize / 2;
75
+ const circleY = rect.y + geometry.squareSize / 2;
76
+ const selectedPieceCode = context.currentFrame.state.board.pieces[interaction.selected.square];
77
+ const targetPieceCode = context.currentFrame.state.board.pieces[destination.to];
78
+ const isCapture = isNonEmptyPieceCode(targetPieceCode) &&
79
+ fromPieceCode(targetPieceCode).color !== fromPieceCode(selectedPieceCode).color;
80
+ const attributes = {
81
+ cx: circleX.toString(),
82
+ cy: circleY.toString(),
83
+ ...(!isCapture ? commonAttributesEmpty : commonAttributesCapture)
84
+ };
85
+ const circle = createSvgElement(internalState.slotRoots.overPieces, 'circle', {
86
+ 'data-chessboard-id': `legal-move-from-${square}-to-${destination.to}`,
87
+ ...attributes
88
+ });
89
+ internalState.svgCircles.push(circle);
90
+ }
91
+ },
92
+ unmount() {
93
+ extensionUnmount(internalState);
94
+ extensionClean(internalState);
95
+ },
96
+ destroy() {
97
+ extensionDestroy(internalState);
98
+ extensionClean(internalState);
99
+ }
100
+ };
101
+ }
@@ -0,0 +1,29 @@
1
+ import { PartialDeep } from 'type-fest';
2
+ import { ExtensionDefinition, ExtensionInstance } from '../../types/extension';
3
+ import { ExtensionInternal, OpaqueColor } from '../common/types';
4
+ export declare const EXTENSION_SLOTS: readonly ["overPieces"];
5
+ export type ExtensionSlotsType = typeof EXTENSION_SLOTS;
6
+ export declare const EXTENSION_ID: "legalMoves";
7
+ export interface LegalMovesConfig {
8
+ emptySquare: {
9
+ color: OpaqueColor;
10
+ radiusRatio: number;
11
+ };
12
+ captureTarget: {
13
+ color: OpaqueColor;
14
+ radiusRatio: number;
15
+ strokeWidthRatio: number;
16
+ };
17
+ }
18
+ export declare const DEFAULT_CONFIG: LegalMovesConfig;
19
+ export type LegalMovesInitConfig = PartialDeep<LegalMovesConfig>;
20
+ export type LegalMovesDefinition = ExtensionDefinition<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
21
+ export type LegalMovesInstance = ExtensionInstance<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
22
+ export interface LegalMovesInstanceInternal extends ExtensionInternal<ExtensionSlotsType> {
23
+ destroyed: boolean;
24
+ svgCircles: SVGCircleElement[];
25
+ readonly config: LegalMovesConfig;
26
+ }
27
+ export declare const enum DirtyLayer {
28
+ Highlight = 1
29
+ }
@@ -0,0 +1,19 @@
1
+ export const EXTENSION_SLOTS = ['overPieces'];
2
+ export const EXTENSION_ID = 'legalMoves';
3
+ export const DEFAULT_CONFIG = {
4
+ emptySquare: {
5
+ color: {
6
+ color: 'rgb(0, 0, 0)',
7
+ opacity: 0.14
8
+ },
9
+ radiusRatio: 0.125
10
+ }, // semi-transparent black
11
+ captureTarget: {
12
+ color: {
13
+ color: 'rgb(0, 0, 0)',
14
+ opacity: 0.14
15
+ },
16
+ radiusRatio: 0.45,
17
+ strokeWidthRatio: 0.1
18
+ }
19
+ };
@@ -0,0 +1,4 @@
1
+ import type { ExtensionRuntimeSurface } from '../../../types/surface/main';
2
+ import type { PieceUrls } from '../types/internal';
3
+ import type { MainRendererAnimation } from './types';
4
+ export declare function createMainRendererAnimation(config: PieceUrls, runtimeSurface: ExtensionRuntimeSurface): MainRendererAnimation;
@@ -0,0 +1,35 @@
1
+ import { cleanAnimationPlan } from '../../../../animation/render/plan';
2
+ import { getAnimationSuppressedSquares, rendererAnimationClean, rendererAnimationPrepare, rendererAnimationRender } from './render';
3
+ import { rendererAnimationOnUpdate } from './update';
4
+ export function createMainRendererAnimation(config, runtimeSurface) {
5
+ const state = {
6
+ config,
7
+ runtimeSurface,
8
+ entries: new Map()
9
+ };
10
+ return {
11
+ onUpdate(context) {
12
+ rendererAnimationOnUpdate(state, context);
13
+ },
14
+ prepareAnimation(context, layer) {
15
+ rendererAnimationPrepare(state, context, layer);
16
+ },
17
+ renderAnimation(context) {
18
+ rendererAnimationRender(state, context);
19
+ },
20
+ cleanAnimation(context) {
21
+ rendererAnimationClean(state, context);
22
+ },
23
+ getSuppressedSquares() {
24
+ return getAnimationSuppressedSquares(state);
25
+ },
26
+ unmount() {
27
+ for (const entry of state.entries.values()) {
28
+ if (entry.nodes !== null) {
29
+ cleanAnimationPlan(entry.nodes);
30
+ }
31
+ }
32
+ state.entries.clear();
33
+ }
34
+ };
35
+ }
@@ -0,0 +1,7 @@
1
+ import type { Square } from '../../../../state/board/types/internal';
2
+ import type { ExtensionCleanAnimationContext, ExtensionPrepareAnimationContext, ExtensionRenderAnimationContext } from '../../../types/context/animation';
3
+ import type { MainRendererAnimationInternal } from './types';
4
+ export declare function rendererAnimationPrepare(state: MainRendererAnimationInternal, context: ExtensionPrepareAnimationContext, layer: SVGElement): void;
5
+ export declare function rendererAnimationRender(state: MainRendererAnimationInternal, context: ExtensionRenderAnimationContext): void;
6
+ export declare function rendererAnimationClean(state: MainRendererAnimationInternal, context: ExtensionCleanAnimationContext): void;
7
+ export declare function getAnimationSuppressedSquares(state: MainRendererAnimationInternal): ReadonlySet<Square>;
@@ -0,0 +1,46 @@
1
+ import { collectSuppressedSquares } from '../../../../animation/planner';
2
+ import { cleanAnimationPlan, prepareAnimationPlan, renderAnimationPlan } from '../../../../animation/render/plan';
3
+ const EMPTY_SQUARES = new Set();
4
+ export function rendererAnimationPrepare(state, context, layer) {
5
+ for (const session of context.submittedSessions) {
6
+ const entry = state.entries.get(session.id);
7
+ if (entry && entry.nodes === null) {
8
+ entry.nodes = prepareAnimationPlan(entry.plan, context.currentFrame.layout.geometry, state.config, layer);
9
+ }
10
+ }
11
+ }
12
+ export function rendererAnimationRender(state, context) {
13
+ for (const session of context.activeSessions) {
14
+ const entry = state.entries.get(session.id);
15
+ if (entry && entry.nodes !== null) {
16
+ renderAnimationPlan(entry.nodes, context.currentFrame.layout.geometry, session.progress);
17
+ }
18
+ }
19
+ }
20
+ export function rendererAnimationClean(state, context) {
21
+ for (const session of context.finishedSessions) {
22
+ const entry = state.entries.get(session.id);
23
+ if (entry) {
24
+ if (entry.nodes !== null) {
25
+ cleanAnimationPlan(entry.nodes);
26
+ }
27
+ state.entries.delete(session.id);
28
+ }
29
+ }
30
+ }
31
+ export function getAnimationSuppressedSquares(state) {
32
+ // get submitted and active animation sessions
33
+ const sessions = state.runtimeSurface.animation.getAll(['submitted', 'active']);
34
+ if (sessions.length === 0)
35
+ return EMPTY_SQUARES;
36
+ const result = new Set();
37
+ for (const session of sessions) {
38
+ const entry = state.entries.get(session.id);
39
+ if (!entry)
40
+ continue;
41
+ for (const sq of collectSuppressedSquares(entry.plan.tracks)) {
42
+ result.add(sq);
43
+ }
44
+ }
45
+ return result;
46
+ }
@@ -0,0 +1,24 @@
1
+ import { PreparedNodeMap } from '../../../../animation/render/types';
2
+ import { AnimationPlan } from '../../../../animation/types';
3
+ import { Square } from '../../../../state/board/types/internal';
4
+ import { ExtensionCleanAnimationContext, ExtensionPrepareAnimationContext, ExtensionRenderAnimationContext } from '../../../types/context/animation';
5
+ import { ExtensionUpdateContext } from '../../../types/context/update';
6
+ import { ExtensionRuntimeSurface } from '../../../types/surface/main';
7
+ import type { PieceUrls } from '../types/internal';
8
+ export interface MainRendererAnimationEntry {
9
+ plan: AnimationPlan;
10
+ nodes: PreparedNodeMap | null;
11
+ }
12
+ export interface MainRendererAnimationInternal {
13
+ readonly config: PieceUrls;
14
+ readonly runtimeSurface: ExtensionRuntimeSurface;
15
+ readonly entries: Map<number, MainRendererAnimationEntry>;
16
+ }
17
+ export interface MainRendererAnimation {
18
+ onUpdate(context: ExtensionUpdateContext): void;
19
+ prepareAnimation(context: ExtensionPrepareAnimationContext, layer: SVGElement): void;
20
+ renderAnimation(context: ExtensionRenderAnimationContext): void;
21
+ cleanAnimation(context: ExtensionCleanAnimationContext): void;
22
+ getSuppressedSquares(): ReadonlySet<Square>;
23
+ unmount(): void;
24
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtensionUpdateContext } from '../../../types/context/update';
2
+ import type { MainRendererAnimationInternal } from './types';
3
+ export declare function rendererAnimationOnUpdate(state: MainRendererAnimationInternal, context: ExtensionUpdateContext): void;
@@ -0,0 +1,40 @@
1
+ import { calculateAnimationPlan } from '../../../../animation/planner';
2
+ import { piecePositionsEqual } from '../../../../state/board/check';
3
+ import { isUpdateContextRenderable } from '../../../types/context/update';
4
+ const DEFAULT_ANIMATION_DURATION_MS = 180;
5
+ export function rendererAnimationOnUpdate(state, context) {
6
+ if (!isUpdateContextRenderable(context) ||
7
+ !context.mutation.hasMutation({ prefixes: ['state.board.'] }) ||
8
+ !context.previousFrame) {
9
+ return;
10
+ }
11
+ const previousBoard = context.previousFrame.state.board;
12
+ const currentBoard = context.currentFrame.state.board;
13
+ if (piecePositionsEqual(previousBoard, currentBoard))
14
+ return;
15
+ // On DropTo exclude the move that user did from the animation plan
16
+ const exclude = [];
17
+ if (context.mutation.hasMutation({ causes: ['runtime.interaction.dropTo'] }) &&
18
+ context.currentFrame.state.change.lastMove) {
19
+ exclude.push({
20
+ fromSq: context.currentFrame.state.change.lastMove.from,
21
+ toSq: context.currentFrame.state.change.lastMove.to
22
+ });
23
+ exclude.push({
24
+ sq: context.currentFrame.state.change.lastMove.from
25
+ });
26
+ exclude.push({
27
+ sq: context.currentFrame.state.change.lastMove.to
28
+ });
29
+ }
30
+ const plan = calculateAnimationPlan(previousBoard, currentBoard, 0 /* placeholder session id for draft plan */, {
31
+ exclude
32
+ });
33
+ if (plan.tracks.length === 0)
34
+ return;
35
+ const session = state.runtimeSurface.animation.submit({
36
+ duration: DEFAULT_ANIMATION_DURATION_MS
37
+ });
38
+ plan.sessionId = session.id;
39
+ state.entries.set(plan.sessionId, { plan, nodes: null });
40
+ }
@@ -0,0 +1,3 @@
1
+ import { ConfigColorPair } from '../types/internal';
2
+ import { MainRendererBoard } from './types';
3
+ export declare function createMainRendererBoard(config: ConfigColorPair): MainRendererBoard;
@@ -0,0 +1,16 @@
1
+ import { rendererBoardRender } from './render';
2
+ import { rendererBoardOnUpdate } from './update';
3
+ function createMainRendererBoardInternal(config) {
4
+ return { config };
5
+ }
6
+ export function createMainRendererBoard(config) {
7
+ const internalState = createMainRendererBoardInternal(config);
8
+ return {
9
+ onUpdate(context) {
10
+ rendererBoardOnUpdate(internalState, context);
11
+ },
12
+ render(context, layer) {
13
+ rendererBoardRender(internalState, context, layer);
14
+ }
15
+ };
16
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtensionRenderContext } from '../../../types/context/render';
2
+ import { MainRendererBoardInternal } from './types';
3
+ export declare function rendererBoardRender(state: MainRendererBoardInternal, context: ExtensionRenderContext, layer: SVGElement): void;
@@ -0,0 +1,24 @@
1
+ import { clearElementChildren, createSvgElement, isLightSquare } from '../../../../render/svg/helpers';
2
+ import { SQUARE_COUNT } from '../../../../state/board/types/internal';
3
+ import { DirtyLayer } from '../types/extension';
4
+ export function rendererBoardRender(state, context, layer) {
5
+ // Check if we need to render
6
+ if ((context.invalidation.dirtyLayers & DirtyLayer.Board) === 0) {
7
+ return; // no-op
8
+ }
9
+ const geometry = context.currentFrame.layout.geometry;
10
+ clearElementChildren(layer);
11
+ const { light, dark } = state.config;
12
+ for (let sq = 0; sq < SQUARE_COUNT; sq++) {
13
+ const r = geometry.squareRect(sq);
14
+ createSvgElement(layer, 'rect', {
15
+ 'data-chessboard-id': `square-${sq}`,
16
+ x: r.x.toString(),
17
+ y: r.y.toString(),
18
+ width: r.size.toString(),
19
+ height: r.size.toString(),
20
+ fill: isLightSquare(sq) ? light : dark,
21
+ 'shape-rendering': 'crispEdges'
22
+ });
23
+ }
24
+ }
@@ -0,0 +1,10 @@
1
+ import { ExtensionRenderContext } from '../../../types/context/render';
2
+ import { ExtensionUpdateContext } from '../../../types/context/update';
3
+ import { ConfigColorPair } from '../types/internal';
4
+ export interface MainRendererBoardInternal {
5
+ readonly config: ConfigColorPair;
6
+ }
7
+ export interface MainRendererBoard {
8
+ onUpdate(context: ExtensionUpdateContext): void;
9
+ render(context: ExtensionRenderContext, layer: SVGElement): void;
10
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtensionUpdateContext } from '../../../types/context/update';
2
+ import { MainRendererBoardInternal } from './types';
3
+ export declare function rendererBoardOnUpdate(_state: MainRendererBoardInternal, context: ExtensionUpdateContext): void;
@@ -0,0 +1,27 @@
1
+ import { isFrameRenderable } from '../../../types/basic/update';
2
+ import { isUpdateContextRenderable } from '../../../types/context/update';
3
+ import { DirtyLayer } from '../types/extension';
4
+ export function rendererBoardOnUpdate(_state, context) {
5
+ // Check if geometry changed
6
+ const mutationSession = context.mutation;
7
+ if (!isUpdateContextRenderable(context) ||
8
+ !mutationSession.hasMutation({
9
+ causes: ['layout.refreshGeometry']
10
+ })) {
11
+ return; // no-op
12
+ }
13
+ // Ok geometry changed, let's check the board size
14
+ const currentGeometry = context.currentFrame.layout.geometry;
15
+ const currentBoardSize = currentGeometry.boardSize;
16
+ const currentOrientation = currentGeometry.orientation;
17
+ const previousGeometry = context.previousFrame && isFrameRenderable(context.previousFrame)
18
+ ? context.previousFrame.layout.geometry
19
+ : null;
20
+ const previousBoardSize = previousGeometry?.boardSize;
21
+ const previousOrientation = previousGeometry?.orientation;
22
+ const needsRender = currentBoardSize !== previousBoardSize || currentOrientation !== previousOrientation;
23
+ if (!needsRender) {
24
+ return; // no-op
25
+ }
26
+ context.invalidation.markDirty(DirtyLayer.Board | DirtyLayer.Coordinates);
27
+ }
@@ -0,0 +1,3 @@
1
+ import { ConfigColorPair } from '../types/internal';
2
+ import { MainRendererCoordinates } from './types';
3
+ export declare function createMainRendererCoordinates(config: ConfigColorPair): MainRendererCoordinates;
@@ -0,0 +1,9 @@
1
+ import { rendererCoordinatesRender } from './render';
2
+ export function createMainRendererCoordinates(config) {
3
+ const internalState = { config };
4
+ return {
5
+ render(context, layer) {
6
+ rendererCoordinatesRender(internalState, context, layer);
7
+ }
8
+ };
9
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtensionRenderContext } from '../../../types/context/render';
2
+ import { MainRendererCoordinatesInternal } from './types';
3
+ export declare function rendererCoordinatesRender(state: MainRendererCoordinatesInternal, context: ExtensionRenderContext, layer: SVGElement): void;
@@ -0,0 +1,60 @@
1
+ import { clearElementChildren, createSvgElement, isLightSquare } from '../../../../render/svg/helpers';
2
+ import { squareOf } from '../../../../state/board/coords';
3
+ import { DirtyLayer } from '../types/extension';
4
+ function labelColorForSquare(sq, coordColors) {
5
+ return isLightSquare(sq) ? coordColors.dark : coordColors.light;
6
+ }
7
+ export function rendererCoordinatesRender(state, context, layer) {
8
+ if ((context.invalidation.dirtyLayers & DirtyLayer.Coordinates) === 0) {
9
+ return;
10
+ }
11
+ const geometry = context.currentFrame.layout.geometry;
12
+ clearElementChildren(layer);
13
+ const coords = state.config;
14
+ const fontSize = geometry.squareSize * 0.12;
15
+ const offset = 3;
16
+ // Rank labels on the visual left edge
17
+ const rankFile = geometry.orientation === 0 /* ColorCode.White */ ? 0 : 7;
18
+ for (let visualRank = 0; visualRank < 8; visualRank++) {
19
+ const logicalRank = (geometry.orientation === 0 /* ColorCode.White */ ? 7 - visualRank : visualRank);
20
+ const sq = squareOf(rankFile, logicalRank);
21
+ const label = geometry.orientation === 0 /* ColorCode.White */ ? String(8 - visualRank) : String(1 + visualRank);
22
+ const r = geometry.squareRect(sq);
23
+ const color = labelColorForSquare(sq, coords);
24
+ const text = createSvgElement(layer, 'text', {
25
+ 'data-chessboard-id': `coord-rank-${label}`,
26
+ x: (r.x + offset).toString(),
27
+ y: (r.y + offset).toString(),
28
+ 'font-size': fontSize.toString(),
29
+ 'font-family': 'sans-serif',
30
+ 'font-weight': 'bold',
31
+ fill: color,
32
+ 'text-anchor': 'start',
33
+ 'dominant-baseline': 'hanging'
34
+ });
35
+ text.textContent = label;
36
+ }
37
+ // File labels on the visual bottom edge
38
+ const fileRank = geometry.orientation === 0 /* ColorCode.White */ ? 0 : 7;
39
+ for (let visualFile = 0; visualFile < 8; visualFile++) {
40
+ const logicalFile = (geometry.orientation === 0 /* ColorCode.White */ ? visualFile : 7 - visualFile);
41
+ const sq = squareOf(logicalFile, fileRank);
42
+ const label = geometry.orientation === 0 /* ColorCode.White */
43
+ ? String.fromCharCode('a'.charCodeAt(0) + visualFile)
44
+ : String.fromCharCode('h'.charCodeAt(0) - visualFile);
45
+ const r = geometry.squareRect(sq);
46
+ const color = labelColorForSquare(sq, coords);
47
+ const text = createSvgElement(layer, 'text', {
48
+ 'data-chessboard-id': `coord-file-${label}`,
49
+ x: (r.x + r.size - offset).toString(),
50
+ y: (r.y + r.size - offset).toString(),
51
+ 'font-size': fontSize.toString(),
52
+ 'font-family': 'sans-serif',
53
+ 'font-weight': 'bold',
54
+ fill: color,
55
+ 'text-anchor': 'end',
56
+ 'dominant-baseline': 'auto'
57
+ });
58
+ text.textContent = label;
59
+ }
60
+ }