@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.
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +96 -0
- package/assets/pieces/chessnut/ATTRIBUTION.md +13 -0
- package/assets/pieces/chessnut/LICENSE.txt +202 -0
- package/assets/pieces/chessnut/bB.svg +58 -0
- package/assets/pieces/chessnut/bK.svg +51 -0
- package/assets/pieces/chessnut/bN.svg +19 -0
- package/assets/pieces/chessnut/bP.svg +17 -0
- package/assets/pieces/chessnut/bQ.svg +97 -0
- package/assets/pieces/chessnut/bR.svg +34 -0
- package/assets/pieces/chessnut/wB.svg +61 -0
- package/assets/pieces/chessnut/wK.svg +71 -0
- package/assets/pieces/chessnut/wN.svg +19 -0
- package/assets/pieces/chessnut/wP.svg +17 -0
- package/assets/pieces/chessnut/wQ.svg +40 -0
- package/assets/pieces/chessnut/wR.svg +38 -0
- package/dist/animation/planner.d.ts +6 -0
- package/dist/animation/planner.js +128 -0
- package/dist/animation/render/fade.d.ts +7 -0
- package/dist/animation/render/fade.js +24 -0
- package/dist/animation/render/move.d.ts +7 -0
- package/dist/animation/render/move.js +28 -0
- package/dist/animation/render/plan.d.ts +14 -0
- package/dist/animation/render/plan.js +69 -0
- package/dist/animation/render/static.d.ts +7 -0
- package/dist/animation/render/static.js +21 -0
- package/dist/animation/render/types.d.ts +21 -0
- package/dist/animation/render/types.js +1 -0
- package/dist/animation/types.d.ts +46 -0
- package/dist/animation/types.js +6 -0
- package/dist/extensions/animation/factory.d.ts +3 -0
- package/dist/extensions/animation/factory.js +88 -0
- package/dist/extensions/animation/types.d.ts +11 -0
- package/dist/extensions/animation/types.js +1 -0
- package/dist/extensions/factory/main.d.ts +2 -0
- package/dist/extensions/factory/main.js +101 -0
- package/dist/extensions/factory/runtime.d.ts +5 -0
- package/dist/extensions/factory/runtime.js +43 -0
- package/dist/extensions/first-party/active-target/factory.d.ts +2 -0
- package/dist/extensions/first-party/active-target/factory.js +109 -0
- package/dist/extensions/first-party/active-target/types.d.ts +25 -0
- package/dist/extensions/first-party/active-target/types.js +15 -0
- package/dist/extensions/first-party/board-events/factory.d.ts +2 -0
- package/dist/extensions/first-party/board-events/factory.js +65 -0
- package/dist/extensions/first-party/board-events/types.d.ts +27 -0
- package/dist/extensions/first-party/board-events/types.js +2 -0
- package/dist/extensions/first-party/common/helpers.d.ts +8 -0
- package/dist/extensions/first-party/common/helpers.js +33 -0
- package/dist/extensions/first-party/common/types.d.ts +10 -0
- package/dist/extensions/first-party/common/types.js +1 -0
- package/dist/extensions/first-party/last-move/factory.d.ts +2 -0
- package/dist/extensions/first-party/last-move/factory.js +106 -0
- package/dist/extensions/first-party/last-move/types.d.ts +19 -0
- package/dist/extensions/first-party/last-move/types.js +6 -0
- package/dist/extensions/first-party/legal-moves/factory.d.ts +2 -0
- package/dist/extensions/first-party/legal-moves/factory.js +101 -0
- package/dist/extensions/first-party/legal-moves/types.d.ts +29 -0
- package/dist/extensions/first-party/legal-moves/types.js +19 -0
- package/dist/extensions/first-party/main-renderer/animation/factory.d.ts +4 -0
- package/dist/extensions/first-party/main-renderer/animation/factory.js +35 -0
- package/dist/extensions/first-party/main-renderer/animation/render.d.ts +7 -0
- package/dist/extensions/first-party/main-renderer/animation/render.js +46 -0
- package/dist/extensions/first-party/main-renderer/animation/types.d.ts +24 -0
- package/dist/extensions/first-party/main-renderer/animation/types.js +1 -0
- package/dist/extensions/first-party/main-renderer/animation/update.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/animation/update.js +40 -0
- package/dist/extensions/first-party/main-renderer/board/factory.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/board/factory.js +16 -0
- package/dist/extensions/first-party/main-renderer/board/render.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/board/render.js +24 -0
- package/dist/extensions/first-party/main-renderer/board/types.d.ts +10 -0
- package/dist/extensions/first-party/main-renderer/board/types.js +1 -0
- package/dist/extensions/first-party/main-renderer/board/update.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/board/update.js +27 -0
- package/dist/extensions/first-party/main-renderer/coordinates/factory.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/coordinates/factory.js +9 -0
- package/dist/extensions/first-party/main-renderer/coordinates/render.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/coordinates/render.js +60 -0
- package/dist/extensions/first-party/main-renderer/coordinates/types.d.ts +8 -0
- package/dist/extensions/first-party/main-renderer/coordinates/types.js +1 -0
- package/dist/extensions/first-party/main-renderer/drag/factory.d.ts +4 -0
- package/dist/extensions/first-party/main-renderer/drag/factory.js +23 -0
- package/dist/extensions/first-party/main-renderer/drag/render.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/drag/render.js +27 -0
- package/dist/extensions/first-party/main-renderer/drag/types.d.ts +16 -0
- package/dist/extensions/first-party/main-renderer/drag/types.js +1 -0
- package/dist/extensions/first-party/main-renderer/drag/update.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/drag/update.js +23 -0
- package/dist/extensions/first-party/main-renderer/factory.d.ts +2 -0
- package/dist/extensions/first-party/main-renderer/factory.js +95 -0
- package/dist/extensions/first-party/main-renderer/normalize.d.ts +4 -0
- package/dist/extensions/first-party/main-renderer/normalize.js +27 -0
- package/dist/extensions/first-party/main-renderer/pieces/factory.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/pieces/factory.js +27 -0
- package/dist/extensions/first-party/main-renderer/pieces/render.d.ts +3 -0
- package/dist/extensions/first-party/main-renderer/pieces/render.js +45 -0
- package/dist/extensions/first-party/main-renderer/pieces/suppress.d.ts +5 -0
- package/dist/extensions/first-party/main-renderer/pieces/suppress.js +9 -0
- package/dist/extensions/first-party/main-renderer/pieces/types.d.ts +20 -0
- package/dist/extensions/first-party/main-renderer/pieces/types.js +1 -0
- package/dist/extensions/first-party/main-renderer/pieces/update.d.ts +6 -0
- package/dist/extensions/first-party/main-renderer/pieces/update.js +31 -0
- package/dist/extensions/first-party/main-renderer/types/extension.d.ts +15 -0
- package/dist/extensions/first-party/main-renderer/types/extension.js +10 -0
- package/dist/extensions/first-party/main-renderer/types/input.d.ts +4 -0
- package/dist/extensions/first-party/main-renderer/types/input.js +1 -0
- package/dist/extensions/first-party/main-renderer/types/instance.d.ts +16 -0
- package/dist/extensions/first-party/main-renderer/types/instance.js +1 -0
- package/dist/extensions/first-party/main-renderer/types/internal.d.ts +17 -0
- package/dist/extensions/first-party/main-renderer/types/internal.js +30 -0
- package/dist/extensions/first-party/main-renderer/types/template.d.ts +5 -0
- package/dist/extensions/first-party/main-renderer/types/template.js +1 -0
- package/dist/extensions/first-party/selected-square/factory.d.ts +2 -0
- package/dist/extensions/first-party/selected-square/factory.js +88 -0
- package/dist/extensions/first-party/selected-square/types.d.ts +18 -0
- package/dist/extensions/first-party/selected-square/types.js +6 -0
- package/dist/extensions/index.d.ts +8 -0
- package/dist/extensions/index.js +6 -0
- package/dist/extensions/invalidation/factory.d.ts +2 -0
- package/dist/extensions/invalidation/factory.js +22 -0
- package/dist/extensions/invalidation/types.d.ts +11 -0
- package/dist/extensions/invalidation/types.js +1 -0
- package/dist/extensions/types/basic/animation.d.ts +28 -0
- package/dist/extensions/types/basic/animation.js +6 -0
- package/dist/extensions/types/basic/events.d.ts +34 -0
- package/dist/extensions/types/basic/events.js +7 -0
- package/dist/extensions/types/basic/mount.d.ts +7 -0
- package/dist/extensions/types/basic/mount.js +14 -0
- package/dist/extensions/types/basic/render.d.ts +9 -0
- package/dist/extensions/types/basic/render.js +1 -0
- package/dist/extensions/types/basic/transient-visuals.d.ts +10 -0
- package/dist/extensions/types/basic/transient-visuals.js +1 -0
- package/dist/extensions/types/basic/update.d.ts +16 -0
- package/dist/extensions/types/basic/update.js +11 -0
- package/dist/extensions/types/context/animation.d.ts +31 -0
- package/dist/extensions/types/context/animation.js +9 -0
- package/dist/extensions/types/context/render.d.ts +6 -0
- package/dist/extensions/types/context/render.js +1 -0
- package/dist/extensions/types/context/transient-visuals.d.ts +7 -0
- package/dist/extensions/types/context/transient-visuals.js +1 -0
- package/dist/extensions/types/context/ui-move.d.ts +16 -0
- package/dist/extensions/types/context/ui-move.js +1 -0
- package/dist/extensions/types/context/update.d.ts +25 -0
- package/dist/extensions/types/context/update.js +10 -0
- package/dist/extensions/types/extension.d.ts +40 -0
- package/dist/extensions/types/extension.js +1 -0
- package/dist/extensions/types/main.d.ts +44 -0
- package/dist/extensions/types/main.js +1 -0
- package/dist/extensions/types/surface/commands.d.ts +26 -0
- package/dist/extensions/types/surface/commands.js +1 -0
- package/dist/extensions/types/surface/events.d.ts +5 -0
- package/dist/extensions/types/surface/events.js +1 -0
- package/dist/extensions/types/surface/main.d.ts +10 -0
- package/dist/extensions/types/surface/main.js +1 -0
- package/dist/extensions/types/surface/transient-visuals.d.ts +4 -0
- package/dist/extensions/types/surface/transient-visuals.js +1 -0
- package/dist/extensions/types/wrapper.d.ts +26 -0
- package/dist/extensions/types/wrapper.js +11 -0
- package/dist/extensions/update.d.ts +4 -0
- package/dist/extensions/update.js +29 -0
- package/dist/helpers/util.d.ts +1 -0
- package/dist/helpers/util.js +9 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/layout/factory.d.ts +2 -0
- package/dist/layout/factory.js +33 -0
- package/dist/layout/geometry/factory.d.ts +12 -0
- package/dist/layout/geometry/factory.js +33 -0
- package/dist/layout/geometry/types.d.ts +20 -0
- package/dist/layout/geometry/types.js +1 -0
- package/dist/layout/helpers.d.ts +4 -0
- package/dist/layout/helpers.js +6 -0
- package/dist/layout/mutation.d.ts +6 -0
- package/dist/layout/mutation.js +1 -0
- package/dist/layout/reducers.d.ts +2 -0
- package/dist/layout/reducers.js +30 -0
- package/dist/layout/types.d.ts +23 -0
- package/dist/layout/types.js +1 -0
- package/dist/mutation/pipeline.d.ts +2 -0
- package/dist/mutation/pipeline.js +36 -0
- package/dist/mutation/session.d.ts +3 -0
- package/dist/mutation/session.js +66 -0
- package/dist/mutation/types.d.ts +26 -0
- package/dist/mutation/types.js +1 -0
- package/dist/render/factory.d.ts +2 -0
- package/dist/render/factory.js +117 -0
- package/dist/render/mount.d.ts +3 -0
- package/dist/render/mount.js +28 -0
- package/dist/render/rendering/animation.d.ts +13 -0
- package/dist/render/rendering/animation.js +92 -0
- package/dist/render/rendering/helpers.d.ts +3 -0
- package/dist/render/rendering/helpers.js +10 -0
- package/dist/render/rendering/state.d.ts +4 -0
- package/dist/render/rendering/state.js +48 -0
- package/dist/render/rendering/visuals.d.ts +3 -0
- package/dist/render/rendering/visuals.js +21 -0
- package/dist/render/scheduler/scheduler.d.ts +2 -0
- package/dist/render/scheduler/scheduler.js +53 -0
- package/dist/render/scheduler/types.d.ts +12 -0
- package/dist/render/scheduler/types.js +1 -0
- package/dist/render/svg/factory.d.ts +4 -0
- package/dist/render/svg/factory.js +38 -0
- package/dist/render/svg/helpers.d.ts +18 -0
- package/dist/render/svg/helpers.js +34 -0
- package/dist/render/types.d.ts +42 -0
- package/dist/render/types.js +1 -0
- package/dist/runtime/factory/helpers.d.ts +6 -0
- package/dist/runtime/factory/helpers.js +42 -0
- package/dist/runtime/factory/input.d.ts +3 -0
- package/dist/runtime/factory/input.js +98 -0
- package/dist/runtime/factory/main.d.ts +2 -0
- package/dist/runtime/factory/main.js +182 -0
- package/dist/runtime/factory/ui-move.d.ts +4 -0
- package/dist/runtime/factory/ui-move.js +84 -0
- package/dist/runtime/input/adapter/factory.d.ts +2 -0
- package/dist/runtime/input/adapter/factory.js +55 -0
- package/dist/runtime/input/adapter/helpers.d.ts +5 -0
- package/dist/runtime/input/adapter/helpers.js +23 -0
- package/dist/runtime/input/adapter/pointer.d.ts +13 -0
- package/dist/runtime/input/adapter/pointer.js +97 -0
- package/dist/runtime/input/adapter/types.d.ts +16 -0
- package/dist/runtime/input/adapter/types.js +1 -0
- package/dist/runtime/input/controller/factory.d.ts +2 -0
- package/dist/runtime/input/controller/factory.js +32 -0
- package/dist/runtime/input/controller/helpers.d.ts +3 -0
- package/dist/runtime/input/controller/helpers.js +12 -0
- package/dist/runtime/input/controller/pointer.d.ts +7 -0
- package/dist/runtime/input/controller/pointer.js +104 -0
- package/dist/runtime/input/controller/transient-visuals.d.ts +3 -0
- package/dist/runtime/input/controller/transient-visuals.js +12 -0
- package/dist/runtime/input/controller/types.d.ts +25 -0
- package/dist/runtime/input/controller/types.js +1 -0
- package/dist/runtime/layout.d.ts +2 -0
- package/dist/runtime/layout.js +10 -0
- package/dist/runtime/lifecycle.d.ts +12 -0
- package/dist/runtime/lifecycle.js +49 -0
- package/dist/runtime/mutation/extension-update.d.ts +2 -0
- package/dist/runtime/mutation/extension-update.js +26 -0
- package/dist/runtime/mutation/factory.d.ts +2 -0
- package/dist/runtime/mutation/factory.js +47 -0
- package/dist/runtime/mutation/interaction.d.ts +2 -0
- package/dist/runtime/mutation/interaction.js +34 -0
- package/dist/runtime/mutation/invalidation.d.ts +0 -0
- package/dist/runtime/mutation/invalidation.js +2 -0
- package/dist/runtime/mutation/last-move.d.ts +3 -0
- package/dist/runtime/mutation/last-move.js +19 -0
- package/dist/runtime/mutation/layout.d.ts +2 -0
- package/dist/runtime/mutation/layout.js +8 -0
- package/dist/runtime/mutation/pipeline.d.ts +22 -0
- package/dist/runtime/mutation/pipeline.js +1 -0
- package/dist/runtime/mutation/request-render.d.ts +2 -0
- package/dist/runtime/mutation/request-render.js +29 -0
- package/dist/runtime/mutation/run.d.ts +2 -0
- package/dist/runtime/mutation/run.js +3 -0
- package/dist/runtime/mutation/types.d.ts +14 -0
- package/dist/runtime/mutation/types.js +1 -0
- package/dist/runtime/types/main.d.ts +36 -0
- package/dist/runtime/types/main.js +1 -0
- package/dist/runtime/types/ui-move.d.ts +9 -0
- package/dist/runtime/types/ui-move.js +1 -0
- package/dist/state/board/check.d.ts +27 -0
- package/dist/state/board/check.js +148 -0
- package/dist/state/board/coords.d.ts +4 -0
- package/dist/state/board/coords.js +9 -0
- package/dist/state/board/denormalize.d.ts +11 -0
- package/dist/state/board/denormalize.js +77 -0
- package/dist/state/board/factory.d.ts +3 -0
- package/dist/state/board/factory.js +46 -0
- package/dist/state/board/mutation.d.ts +9 -0
- package/dist/state/board/mutation.js +1 -0
- package/dist/state/board/normalize.d.ts +8 -0
- package/dist/state/board/normalize.js +76 -0
- package/dist/state/board/piece.d.ts +3 -0
- package/dist/state/board/piece.js +11 -0
- package/dist/state/board/position.d.ts +4 -0
- package/dist/state/board/position.js +94 -0
- package/dist/state/board/reducers.d.ts +8 -0
- package/dist/state/board/reducers.js +80 -0
- package/dist/state/board/types/input.d.ts +35 -0
- package/dist/state/board/types/input.js +1 -0
- package/dist/state/board/types/internal.d.ts +54 -0
- package/dist/state/board/types/internal.js +17 -0
- package/dist/state/board/types/main.d.ts +18 -0
- package/dist/state/board/types/main.js +1 -0
- package/dist/state/board/types/output.d.ts +5 -0
- package/dist/state/board/types/output.js +1 -0
- package/dist/state/board/types/template.d.ts +23 -0
- package/dist/state/board/types/template.js +1 -0
- package/dist/state/change/factory.d.ts +2 -0
- package/dist/state/change/factory.js +28 -0
- package/dist/state/change/helpers.d.ts +8 -0
- package/dist/state/change/helpers.js +86 -0
- package/dist/state/change/mutation.d.ts +6 -0
- package/dist/state/change/mutation.js +1 -0
- package/dist/state/change/reducers.d.ts +5 -0
- package/dist/state/change/reducers.js +16 -0
- package/dist/state/change/types.d.ts +17 -0
- package/dist/state/change/types.js +1 -0
- package/dist/state/factory.d.ts +2 -0
- package/dist/state/factory.js +24 -0
- package/dist/state/interaction/factory.d.ts +2 -0
- package/dist/state/interaction/factory.js +83 -0
- package/dist/state/interaction/helpers.d.ts +4 -0
- package/dist/state/interaction/helpers.js +16 -0
- package/dist/state/interaction/movability.d.ts +5 -0
- package/dist/state/interaction/movability.js +87 -0
- package/dist/state/interaction/mutation.d.ts +11 -0
- package/dist/state/interaction/mutation.js +1 -0
- package/dist/state/interaction/normalize.d.ts +5 -0
- package/dist/state/interaction/normalize.js +50 -0
- package/dist/state/interaction/reducers.d.ts +11 -0
- package/dist/state/interaction/reducers.js +81 -0
- package/dist/state/interaction/types/input.d.ts +18 -0
- package/dist/state/interaction/types/input.js +1 -0
- package/dist/state/interaction/types/internal.d.ts +35 -0
- package/dist/state/interaction/types/internal.js +1 -0
- package/dist/state/interaction/types/main.d.ts +33 -0
- package/dist/state/interaction/types/main.js +1 -0
- package/dist/state/types.d.ts +30 -0
- package/dist/state/types.js +1 -0
- package/dist/state/view/factory.d.ts +2 -0
- package/dist/state/view/factory.js +24 -0
- package/dist/state/view/mutation.d.ts +5 -0
- package/dist/state/view/mutation.js +1 -0
- package/dist/state/view/reducers.d.ts +3 -0
- package/dist/state/view/reducers.js +6 -0
- package/dist/state/view/types/internal.d.ts +6 -0
- package/dist/state/view/types/internal.js +1 -0
- package/dist/state/view/types/main.d.ts +12 -0
- package/dist/state/view/types/main.js +1 -0
- package/dist/wrapper/factory.d.ts +3 -0
- package/dist/wrapper/factory.js +61 -0
- package/dist/wrapper/types.d.ts +56 -0
- package/dist/wrapper/types.js +1 -0
- 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,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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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,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,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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 { 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
|
+
}
|