@mirasen/chessboard 1.1.5 → 1.2.1
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 +45 -0
- package/README.md +61 -13
- package/dist/animation/render/fade.d.ts +2 -3
- package/dist/animation/render/fade.js +6 -6
- package/dist/animation/render/move.d.ts +2 -3
- package/dist/animation/render/move.js +6 -6
- package/dist/animation/render/plan.d.ts +3 -4
- package/dist/animation/render/plan.js +5 -5
- package/dist/animation/render/static.d.ts +2 -3
- package/dist/animation/render/static.js +4 -4
- package/dist/animation/render/types.d.ts +10 -4
- package/dist/extensions/build/index.d.ts +1 -2
- package/dist/extensions/build/index.js +1 -1
- package/dist/extensions/factory/main.js +11 -7
- package/dist/extensions/factory/runtime.js +24 -1
- package/dist/extensions/first-party/active-target/factory.js +18 -11
- package/dist/extensions/first-party/annotations/api.d.ts +16 -0
- package/dist/extensions/first-party/annotations/api.js +79 -0
- package/dist/extensions/first-party/annotations/committed.d.ts +3 -0
- package/dist/extensions/first-party/annotations/committed.js +11 -0
- package/dist/extensions/first-party/annotations/constants.d.ts +3 -0
- package/dist/extensions/first-party/annotations/constants.js +54 -0
- package/dist/extensions/first-party/annotations/denormalize.d.ts +4 -0
- package/dist/extensions/first-party/annotations/denormalize.js +22 -0
- package/dist/extensions/first-party/annotations/factory.d.ts +3 -0
- package/dist/extensions/first-party/annotations/factory.js +143 -0
- package/dist/extensions/first-party/annotations/interaction.d.ts +8 -0
- package/dist/extensions/first-party/annotations/interaction.js +129 -0
- package/dist/extensions/first-party/annotations/invalidation.d.ts +3 -0
- package/dist/extensions/first-party/annotations/invalidation.js +7 -0
- package/dist/extensions/first-party/annotations/normalize.d.ts +12 -0
- package/dist/extensions/first-party/annotations/normalize.js +54 -0
- package/dist/extensions/first-party/annotations/render/committed.d.ts +3 -0
- package/dist/extensions/first-party/annotations/render/committed.js +123 -0
- package/dist/extensions/first-party/annotations/render/helpers/arrows.d.ts +33 -0
- package/dist/extensions/first-party/annotations/render/helpers/arrows.js +93 -0
- package/dist/extensions/first-party/annotations/render/helpers/circles.d.ts +18 -0
- package/dist/extensions/first-party/annotations/render/helpers/circles.js +30 -0
- package/dist/extensions/first-party/annotations/render/preview.d.ts +3 -0
- package/dist/extensions/first-party/annotations/render/preview.js +96 -0
- package/dist/extensions/first-party/annotations/types/internal.d.ts +77 -0
- package/dist/extensions/first-party/annotations/types/internal.js +1 -0
- package/dist/extensions/first-party/annotations/types/main.d.ts +40 -0
- package/dist/extensions/first-party/annotations/types/main.js +6 -0
- package/dist/extensions/first-party/annotations/types/public.d.ts +48 -0
- package/dist/extensions/first-party/annotations/types/public.js +1 -0
- package/dist/extensions/first-party/annotations/update.d.ts +3 -0
- package/dist/extensions/first-party/annotations/update.js +45 -0
- package/dist/extensions/first-party/auto-promote/factory.js +6 -6
- package/dist/extensions/first-party/board-events/factory.js +6 -6
- package/dist/extensions/first-party/common/helpers.d.ts +2 -1
- package/dist/extensions/first-party/common/helpers.js +6 -5
- package/dist/extensions/first-party/common/types.d.ts +2 -0
- package/dist/extensions/first-party/last-move/factory.js +9 -9
- package/dist/extensions/first-party/legal-moves/factory.js +8 -8
- package/dist/extensions/first-party/main-renderer/animation/factory.d.ts +2 -2
- package/dist/extensions/first-party/main-renderer/animation/factory.js +4 -4
- package/dist/extensions/first-party/main-renderer/animation/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/animation/render.js +2 -2
- package/dist/extensions/first-party/main-renderer/animation/types.d.ts +3 -3
- package/dist/extensions/first-party/main-renderer/board/factory.js +2 -2
- package/dist/extensions/first-party/main-renderer/board/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/board/render.js +4 -4
- package/dist/extensions/first-party/main-renderer/board/types.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/coordinates/factory.js +2 -2
- package/dist/extensions/first-party/main-renderer/coordinates/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/coordinates/render.js +5 -5
- package/dist/extensions/first-party/main-renderer/coordinates/types.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/drag/factory.d.ts +2 -2
- package/dist/extensions/first-party/main-renderer/drag/factory.js +11 -8
- package/dist/extensions/first-party/main-renderer/drag/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/drag/render.js +7 -6
- package/dist/extensions/first-party/main-renderer/drag/types.d.ts +6 -5
- package/dist/extensions/first-party/main-renderer/drag/update.js +2 -2
- package/dist/extensions/first-party/main-renderer/factory.js +9 -5
- package/dist/extensions/first-party/main-renderer/piece-symbols.d.ts +19 -0
- package/dist/extensions/first-party/main-renderer/piece-symbols.js +45 -0
- package/dist/extensions/first-party/main-renderer/pieces/factory.d.ts +2 -2
- package/dist/extensions/first-party/main-renderer/pieces/factory.js +4 -4
- package/dist/extensions/first-party/main-renderer/pieces/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/pieces/render.js +8 -8
- package/dist/extensions/first-party/main-renderer/pieces/types.d.ts +4 -4
- package/dist/extensions/first-party/main-renderer/types/extension.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/types/extension.js +8 -1
- package/dist/extensions/first-party/main-renderer/types/instance.d.ts +2 -0
- package/dist/extensions/first-party/promotion/factory.js +10 -10
- package/dist/extensions/first-party/selected-square/factory.js +8 -8
- package/dist/extensions/first-party/watermark/factory.js +8 -8
- package/dist/extensions/types/basic/events.d.ts +32 -3
- package/dist/extensions/types/basic/events.js +2 -1
- package/dist/extensions/types/basic/mount.d.ts +5 -2
- package/dist/extensions/types/basic/mount.js +0 -2
- package/dist/extensions/types/basic/transient-visuals.d.ts +1 -1
- package/dist/extensions/types/context/animation.d.ts +3 -3
- package/dist/extensions/types/context/events.d.ts +2 -1
- package/dist/extensions/types/context/update.d.ts +6 -7
- package/dist/extensions/types/extension.d.ts +3 -0
- package/dist/extensions/types/main.d.ts +1 -0
- package/dist/extensions/types/surface/commands.d.ts +1 -1
- package/dist/extensions/types/surface/main.d.ts +6 -4
- package/dist/extensions/types/wrapper.d.ts +3 -1
- package/dist/extensions/types/wrapper.js +6 -2
- package/dist/extensions/update.js +6 -10
- package/dist/index.d.ts +1 -1
- package/dist/render/mount.js +3 -3
- package/dist/render/rendering/state.js +2 -2
- package/dist/render/svg/factory.js +40 -25
- package/dist/render/svg/helpers.d.ts +8 -4
- package/dist/render/svg/helpers.js +27 -12
- package/dist/render/svg/ids.d.ts +6 -0
- package/dist/render/svg/ids.js +11 -0
- package/dist/render/types.d.ts +4 -3
- package/dist/render/types.js +2 -1
- package/dist/runtime/factory/input.d.ts +3 -1
- package/dist/runtime/factory/input.js +11 -2
- package/dist/runtime/factory/main.js +10 -4
- package/dist/runtime/input/adapter/event.js +2 -2
- package/dist/runtime/input/adapter/pointer.d.ts +2 -2
- package/dist/runtime/input/controller/factory.d.ts +1 -1
- package/dist/runtime/input/controller/factory.js +35 -15
- package/dist/runtime/input/controller/helpers.d.ts +1 -1
- package/dist/runtime/input/controller/interaction.d.ts +3 -0
- package/dist/runtime/input/controller/interaction.js +14 -0
- package/dist/runtime/input/controller/pointer.d.ts +6 -6
- package/dist/runtime/input/controller/pointer.js +53 -27
- package/dist/runtime/input/controller/transient-visuals.d.ts +2 -3
- package/dist/runtime/input/controller/types.d.ts +6 -5
- package/dist/runtime/types/main.d.ts +1 -1
- package/dist/wrapper/factory.js +2 -7
- package/dist/wrapper/types.d.ts +3 -11
- package/package.json +1 -2
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { normalizeSquare } from '../../../state/board/normalize.js';
|
|
2
|
+
import { denormalizeArrows, denormalizeCircles } from './denormalize.js';
|
|
3
|
+
import { markCommittedDirtyAndRequestRender } from './invalidation.js';
|
|
4
|
+
import { arrowAnnotationKey, normalizeArrowAnnotation, normalizeCircleAnnotation } from './normalize.js';
|
|
5
|
+
export function annotationsGetCircles(state) {
|
|
6
|
+
return denormalizeCircles(state.annotations.circles);
|
|
7
|
+
}
|
|
8
|
+
export function annotationsGetArrows(state) {
|
|
9
|
+
return denormalizeArrows(state.annotations.arrows);
|
|
10
|
+
}
|
|
11
|
+
export function annotationsSetCircles(state, circles) {
|
|
12
|
+
state.annotations.circles.clear();
|
|
13
|
+
for (const pub of circles) {
|
|
14
|
+
const circle = normalizeCircleAnnotation(pub);
|
|
15
|
+
state.annotations.circles.set(circle.key, circle);
|
|
16
|
+
}
|
|
17
|
+
markCommittedDirtyAndRequestRender(state);
|
|
18
|
+
}
|
|
19
|
+
export function annotationsSetArrows(state, arrows) {
|
|
20
|
+
// Validate all entries before mutating state (atomic behavior)
|
|
21
|
+
const normalized = arrows.map((pub) => normalizeArrowAnnotation(pub));
|
|
22
|
+
state.annotations.arrows.clear();
|
|
23
|
+
for (const arrow of normalized) {
|
|
24
|
+
state.annotations.arrows.set(arrow.key, arrow);
|
|
25
|
+
}
|
|
26
|
+
markCommittedDirtyAndRequestRender(state);
|
|
27
|
+
}
|
|
28
|
+
export function annotationsSetCircle(state, square, annotation) {
|
|
29
|
+
const key = normalizeSquare(square);
|
|
30
|
+
if (annotation === null) {
|
|
31
|
+
state.annotations.circles.delete(key);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const normalizedAnnotation = normalizeCircleAnnotation({
|
|
35
|
+
square,
|
|
36
|
+
color: annotation.color
|
|
37
|
+
});
|
|
38
|
+
state.annotations.circles.set(key, normalizedAnnotation);
|
|
39
|
+
}
|
|
40
|
+
markCommittedDirtyAndRequestRender(state);
|
|
41
|
+
}
|
|
42
|
+
export function annotationsSetArrow(state, from, to, annotation) {
|
|
43
|
+
const key = arrowAnnotationKey(from, to);
|
|
44
|
+
if (annotation === null) {
|
|
45
|
+
state.annotations.arrows.delete(key);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const normalizedArrow = normalizeArrowAnnotation({
|
|
49
|
+
from,
|
|
50
|
+
to,
|
|
51
|
+
color: annotation.color
|
|
52
|
+
});
|
|
53
|
+
state.annotations.arrows.set(key, normalizedArrow);
|
|
54
|
+
}
|
|
55
|
+
markCommittedDirtyAndRequestRender(state);
|
|
56
|
+
}
|
|
57
|
+
export function annotationsClear(state) {
|
|
58
|
+
state.annotations.circles.clear();
|
|
59
|
+
state.annotations.arrows.clear();
|
|
60
|
+
markCommittedDirtyAndRequestRender(state);
|
|
61
|
+
}
|
|
62
|
+
export function annotationsSetClearOnCoreInteraction(state, value) {
|
|
63
|
+
state.config.clearOnCoreInteraction = value;
|
|
64
|
+
}
|
|
65
|
+
export function annotationsGetClearOnCoreInteraction(state) {
|
|
66
|
+
return state.config.clearOnCoreInteraction;
|
|
67
|
+
}
|
|
68
|
+
export function annotationsSetDrawButton(state, value) {
|
|
69
|
+
state.config.drawButton = value;
|
|
70
|
+
}
|
|
71
|
+
export function annotationsGetDrawButton(state) {
|
|
72
|
+
return state.config.drawButton;
|
|
73
|
+
}
|
|
74
|
+
export function annotationsSetDrawModifier(state, value) {
|
|
75
|
+
state.config.drawModifier = value;
|
|
76
|
+
}
|
|
77
|
+
export function annotationsGetDrawModifier(state) {
|
|
78
|
+
return state.config.drawModifier;
|
|
79
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function hasCommittedAnnotations(state) {
|
|
2
|
+
return state.annotations.circles.size > 0 || state.annotations.arrows.size > 0;
|
|
3
|
+
}
|
|
4
|
+
export function clearCommittedAnnotations(state) {
|
|
5
|
+
if (state.annotations.circles.size === 0 && state.annotations.arrows.size === 0) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
state.annotations.circles.clear();
|
|
9
|
+
state.annotations.arrows.clear();
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const DEFAULT_CONFIG = {
|
|
2
|
+
clearOnCoreInteraction: true,
|
|
3
|
+
colors: {
|
|
4
|
+
none: '#15781B',
|
|
5
|
+
ctrl: '#882020',
|
|
6
|
+
shift: '#e68f00',
|
|
7
|
+
alt: '#003088',
|
|
8
|
+
meta: '#6f2da8'
|
|
9
|
+
},
|
|
10
|
+
drawButton: 2,
|
|
11
|
+
drawModifier: null
|
|
12
|
+
};
|
|
13
|
+
export const VISUAL_CONFIG = {
|
|
14
|
+
circle: {
|
|
15
|
+
committed: {
|
|
16
|
+
strokeWidth: 0.0625,
|
|
17
|
+
radius: 0.46875,
|
|
18
|
+
opacity: 1
|
|
19
|
+
},
|
|
20
|
+
previewAdd: {
|
|
21
|
+
strokeWidth: 0.05,
|
|
22
|
+
radius: 0.46875,
|
|
23
|
+
opacity: 0.8
|
|
24
|
+
},
|
|
25
|
+
previewRemoveOpacity: 0.25
|
|
26
|
+
},
|
|
27
|
+
arrow: {
|
|
28
|
+
committed: {
|
|
29
|
+
strokeWidth: 0.15625,
|
|
30
|
+
startOffset: 0,
|
|
31
|
+
endOffset: 0.15625,
|
|
32
|
+
opacity: 0.75,
|
|
33
|
+
markerWidth: 4,
|
|
34
|
+
markerHeight: 4,
|
|
35
|
+
markerRefX: 2.05,
|
|
36
|
+
markerRefY: 2,
|
|
37
|
+
markerViewBox: '0 0 4 4',
|
|
38
|
+
markerPathD: 'M0,0 V4 L3,2 Z'
|
|
39
|
+
},
|
|
40
|
+
previewAdd: {
|
|
41
|
+
strokeWidth: 0.11,
|
|
42
|
+
startOffset: 0,
|
|
43
|
+
endOffset: 0.15625,
|
|
44
|
+
opacity: 0.55,
|
|
45
|
+
markerWidth: 4,
|
|
46
|
+
markerHeight: 4,
|
|
47
|
+
markerRefX: 2.05,
|
|
48
|
+
markerRefY: 2,
|
|
49
|
+
markerViewBox: '0 0 4 4',
|
|
50
|
+
markerPathD: 'M0,0 V4 L3,2 Z'
|
|
51
|
+
},
|
|
52
|
+
previewRemoveOpacity: 0.25
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ArrowAnnotation, ArrowAnnotationKey, CircleAnnotation, CircleAnnotationKey } from './types/internal.js';
|
|
2
|
+
import type { ArrowAnnotationPublic, CircleAnnotationPublic } from './types/public.js';
|
|
3
|
+
export declare function denormalizeCircles(circles: Map<CircleAnnotationKey, CircleAnnotation>): CircleAnnotationPublic[];
|
|
4
|
+
export declare function denormalizeArrows(arrows: Map<ArrowAnnotationKey, ArrowAnnotation>): ArrowAnnotationPublic[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { denormalizeSquare } from '../../../state/board/denormalize.js';
|
|
2
|
+
export function denormalizeCircles(circles) {
|
|
3
|
+
const result = [];
|
|
4
|
+
for (const circle of circles.values()) {
|
|
5
|
+
result.push({
|
|
6
|
+
square: denormalizeSquare(circle.square),
|
|
7
|
+
color: circle.color
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
export function denormalizeArrows(arrows) {
|
|
13
|
+
const result = [];
|
|
14
|
+
for (const arrow of arrows.values()) {
|
|
15
|
+
result.push({
|
|
16
|
+
from: denormalizeSquare(arrow.from),
|
|
17
|
+
to: denormalizeSquare(arrow.to),
|
|
18
|
+
color: arrow.color
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { cloneDeep } from 'es-toolkit';
|
|
2
|
+
import { extensionCreateInternalBase, extensionDestroyBase, extensionMountBase, extensionUnmountBase } from '../common/helpers.js';
|
|
3
|
+
import { annotationsClear, annotationsGetArrows, annotationsGetCircles, annotationsGetClearOnCoreInteraction, annotationsGetDrawButton, annotationsGetDrawModifier, annotationsSetArrow, annotationsSetArrows, annotationsSetCircle, annotationsSetCircles, annotationsSetClearOnCoreInteraction, annotationsSetDrawButton, annotationsSetDrawModifier } from './api.js';
|
|
4
|
+
import { cancelAnnotationsDrag, completeAnnotationsDrag, handleAnnotationsEvent } from './interaction.js';
|
|
5
|
+
import { normalizeAnnotationsConfig, normalizeInitialAnnotations } from './normalize.js';
|
|
6
|
+
import { renderCommittedAnnotations } from './render/committed.js';
|
|
7
|
+
import { renderPreviewAnnotations } from './render/preview.js';
|
|
8
|
+
import { EXTENSION_ID, EXTENSION_SLOTS } from './types/main.js';
|
|
9
|
+
import { annotationsOnUpdate } from './update.js';
|
|
10
|
+
export function createAnnotations(options = {}) {
|
|
11
|
+
const normalizedConfig = normalizeAnnotationsConfig(options.config);
|
|
12
|
+
const normalizedAnnotations = normalizeInitialAnnotations(options.annotations);
|
|
13
|
+
return {
|
|
14
|
+
id: EXTENSION_ID,
|
|
15
|
+
slots: EXTENSION_SLOTS,
|
|
16
|
+
createInstance(runtimeOptions) {
|
|
17
|
+
return createAnnotationsInstance(normalizedConfig, normalizedAnnotations, runtimeOptions);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function createAnnotationsInternal(normalizedConfig, normalizedAnnotations, runtimeOptions) {
|
|
22
|
+
// Clone to ensure each instance has independent mutable state
|
|
23
|
+
const config = cloneDeep(normalizedConfig);
|
|
24
|
+
const annotations = {
|
|
25
|
+
circles: new Map(normalizedAnnotations.circles),
|
|
26
|
+
arrows: new Map(normalizedAnnotations.arrows)
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
...extensionCreateInternalBase(runtimeOptions),
|
|
30
|
+
runtimeSurface: runtimeOptions.runtimeSurface,
|
|
31
|
+
svg: {
|
|
32
|
+
svgCircles: new Map(),
|
|
33
|
+
svgArrows: new Map()
|
|
34
|
+
},
|
|
35
|
+
annotations,
|
|
36
|
+
config,
|
|
37
|
+
activeDrawGesture: null,
|
|
38
|
+
activeDrawPreviewTarget: null,
|
|
39
|
+
previewSvg: { circle: null, arrow: null }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function extensionCleanSvg(state) {
|
|
43
|
+
state.svg.svgCircles.clear();
|
|
44
|
+
state.svg.svgArrows.clear();
|
|
45
|
+
if (state.previewSvg.arrow) {
|
|
46
|
+
state.previewSvg.arrow.marker.remove();
|
|
47
|
+
}
|
|
48
|
+
state.previewSvg.circle = null;
|
|
49
|
+
state.previewSvg.arrow = null;
|
|
50
|
+
}
|
|
51
|
+
function extensionClean(state) {
|
|
52
|
+
state.runtimeSurface.events.unsubscribeEvent('pointerdown');
|
|
53
|
+
state.runtimeSurface.events.unsubscribeEvent('contextmenu');
|
|
54
|
+
state.activeDrawGesture = null;
|
|
55
|
+
state.activeDrawPreviewTarget = null;
|
|
56
|
+
extensionCleanSvg(state);
|
|
57
|
+
}
|
|
58
|
+
function createAnnotationsPublicAPI(state) {
|
|
59
|
+
return {
|
|
60
|
+
getCircles() {
|
|
61
|
+
return annotationsGetCircles(state);
|
|
62
|
+
},
|
|
63
|
+
getArrows() {
|
|
64
|
+
return annotationsGetArrows(state);
|
|
65
|
+
},
|
|
66
|
+
setCircles(circles) {
|
|
67
|
+
annotationsSetCircles(state, circles);
|
|
68
|
+
},
|
|
69
|
+
setArrows(arrows) {
|
|
70
|
+
annotationsSetArrows(state, arrows);
|
|
71
|
+
},
|
|
72
|
+
circle(square, annotation) {
|
|
73
|
+
annotationsSetCircle(state, square, annotation);
|
|
74
|
+
},
|
|
75
|
+
arrow(from, to, annotation) {
|
|
76
|
+
annotationsSetArrow(state, from, to, annotation);
|
|
77
|
+
},
|
|
78
|
+
clear() {
|
|
79
|
+
annotationsClear(state);
|
|
80
|
+
},
|
|
81
|
+
get clearOnCoreInteraction() {
|
|
82
|
+
return annotationsGetClearOnCoreInteraction(state);
|
|
83
|
+
},
|
|
84
|
+
set clearOnCoreInteraction(value) {
|
|
85
|
+
annotationsSetClearOnCoreInteraction(state, value);
|
|
86
|
+
},
|
|
87
|
+
get drawButton() {
|
|
88
|
+
return annotationsGetDrawButton(state);
|
|
89
|
+
},
|
|
90
|
+
set drawButton(value) {
|
|
91
|
+
annotationsSetDrawButton(state, value);
|
|
92
|
+
},
|
|
93
|
+
get drawModifier() {
|
|
94
|
+
return annotationsGetDrawModifier(state);
|
|
95
|
+
},
|
|
96
|
+
set drawModifier(value) {
|
|
97
|
+
annotationsSetDrawModifier(state, value);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function createAnnotationsInstance(normalizedConfig, normalizedAnnotations, runtimeOptions) {
|
|
102
|
+
const internalState = createAnnotationsInternal(normalizedConfig, normalizedAnnotations, runtimeOptions);
|
|
103
|
+
const publicAPI = createAnnotationsPublicAPI(internalState);
|
|
104
|
+
return {
|
|
105
|
+
id: EXTENSION_ID,
|
|
106
|
+
mount(env) {
|
|
107
|
+
extensionMountBase(internalState, env.slotRoots);
|
|
108
|
+
internalState.runtimeSurface.events.subscribeEvent('pointerdown');
|
|
109
|
+
internalState.runtimeSurface.events.subscribeEvent('contextmenu');
|
|
110
|
+
},
|
|
111
|
+
onUpdate(context) {
|
|
112
|
+
annotationsOnUpdate(internalState, context);
|
|
113
|
+
},
|
|
114
|
+
render(context) {
|
|
115
|
+
if (context.invalidation.dirtyLayers & 1 /* DirtyLayer.COMMITTED */) {
|
|
116
|
+
renderCommittedAnnotations(internalState, context.currentFrame.layout.geometry);
|
|
117
|
+
}
|
|
118
|
+
if (context.invalidation.dirtyLayers & 2 /* DirtyLayer.PREVIEW */) {
|
|
119
|
+
renderPreviewAnnotations(internalState, context.currentFrame.layout.geometry);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
onEvent(context) {
|
|
123
|
+
handleAnnotationsEvent(internalState, context);
|
|
124
|
+
},
|
|
125
|
+
completeDrag(session) {
|
|
126
|
+
completeAnnotationsDrag(internalState, session);
|
|
127
|
+
},
|
|
128
|
+
cancelDrag(session) {
|
|
129
|
+
cancelAnnotationsDrag(internalState, session);
|
|
130
|
+
},
|
|
131
|
+
unmount() {
|
|
132
|
+
extensionClean(internalState);
|
|
133
|
+
extensionUnmountBase(internalState);
|
|
134
|
+
},
|
|
135
|
+
destroy() {
|
|
136
|
+
extensionClean(internalState);
|
|
137
|
+
extensionDestroyBase(internalState);
|
|
138
|
+
},
|
|
139
|
+
getPublic() {
|
|
140
|
+
return publicAPI;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExtensionDragSessionSnapshot } from '../../types/basic/interaction.js';
|
|
2
|
+
import type { ExtensionOnEventContext } from '../../types/context/events.js';
|
|
3
|
+
import type { AnnotationColor, AnnotationsConfig } from './types/internal.js';
|
|
4
|
+
import type { AnnotationsStateInternal } from './types/main.js';
|
|
5
|
+
export declare function resolveAnnotationColor(config: AnnotationsConfig, rawEvent: PointerEvent): AnnotationColor;
|
|
6
|
+
export declare function handleAnnotationsEvent(state: AnnotationsStateInternal, context: ExtensionOnEventContext): void;
|
|
7
|
+
export declare function completeAnnotationsDrag(state: AnnotationsStateInternal, session: ExtensionDragSessionSnapshot): void;
|
|
8
|
+
export declare function cancelAnnotationsDrag(state: AnnotationsStateInternal, session: ExtensionDragSessionSnapshot): void;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import assert from '@ktarmyshov/assert';
|
|
2
|
+
import { clearCommittedAnnotations, hasCommittedAnnotations } from './committed.js';
|
|
3
|
+
import { markCommittedDirtyAndRequestRender } from './invalidation.js';
|
|
4
|
+
import { arrowAnnotationKeyNormalized } from './normalize.js';
|
|
5
|
+
const ANNOTATIONS_IDLE_CLEAR_DRAG_TYPE = 'ext:idle-clear';
|
|
6
|
+
const ANNOTATIONS_DRAW_DRAG_TYPE = 'ext:draw';
|
|
7
|
+
export function resolveAnnotationColor(config, rawEvent) {
|
|
8
|
+
if (config.drawModifier != null) {
|
|
9
|
+
return config.colors[config.drawModifier];
|
|
10
|
+
}
|
|
11
|
+
if (rawEvent.ctrlKey)
|
|
12
|
+
return config.colors.ctrl;
|
|
13
|
+
if (rawEvent.shiftKey)
|
|
14
|
+
return config.colors.shift;
|
|
15
|
+
if (rawEvent.altKey)
|
|
16
|
+
return config.colors.alt;
|
|
17
|
+
if (rawEvent.metaKey)
|
|
18
|
+
return config.colors.meta;
|
|
19
|
+
return config.colors.none;
|
|
20
|
+
}
|
|
21
|
+
export function handleAnnotationsEvent(state, context) {
|
|
22
|
+
assert(context.rawEvent.type === 'pointerdown' || context.rawEvent.type === 'contextmenu');
|
|
23
|
+
if (context.rawEvent.type === 'contextmenu') {
|
|
24
|
+
// Browser context menus are separate from the pointer drag lifecycle.
|
|
25
|
+
// The board owns secondary-button interaction, so suppress the browser menu.
|
|
26
|
+
context.rawEvent.preventDefault();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const rawEvent = context.rawEvent;
|
|
30
|
+
// The configured draw button owns annotation drawing gestures.
|
|
31
|
+
// If configured as primary, drawing intentionally takes precedence over idle-clear.
|
|
32
|
+
if (rawEvent.button === state.config.drawButton) {
|
|
33
|
+
const targetSquare = context.sceneEvent?.targetSquare;
|
|
34
|
+
if (targetSquare === undefined || targetSquare === null)
|
|
35
|
+
return;
|
|
36
|
+
state.activeDrawGesture = {
|
|
37
|
+
sourceSquare: targetSquare,
|
|
38
|
+
color: resolveAnnotationColor(state.config, rawEvent)
|
|
39
|
+
};
|
|
40
|
+
const success = state.runtimeSurface.commands.startDrag({
|
|
41
|
+
type: ANNOTATIONS_DRAW_DRAG_TYPE,
|
|
42
|
+
sourceSquare: targetSquare,
|
|
43
|
+
sourcePieceCode: null,
|
|
44
|
+
targetSquare: targetSquare
|
|
45
|
+
});
|
|
46
|
+
if (success) {
|
|
47
|
+
rawEvent.preventDefault();
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
state.activeDrawGesture = null;
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Drawing uses the configured draw button above.
|
|
55
|
+
// The remaining primary-button path is reserved for idle-clear.
|
|
56
|
+
if (rawEvent.button !== 0)
|
|
57
|
+
return;
|
|
58
|
+
const targetSquare = context.sceneEvent?.targetSquare;
|
|
59
|
+
if (targetSquare === undefined || targetSquare === null)
|
|
60
|
+
return;
|
|
61
|
+
if (context.runtimeInteractionActionPreview !== null)
|
|
62
|
+
return;
|
|
63
|
+
if (!state.config.clearOnCoreInteraction)
|
|
64
|
+
return;
|
|
65
|
+
if (!hasCommittedAnnotations(state))
|
|
66
|
+
return;
|
|
67
|
+
const success = state.runtimeSurface.commands.startDrag({
|
|
68
|
+
type: ANNOTATIONS_IDLE_CLEAR_DRAG_TYPE,
|
|
69
|
+
sourceSquare: targetSquare,
|
|
70
|
+
sourcePieceCode: null,
|
|
71
|
+
targetSquare: targetSquare
|
|
72
|
+
});
|
|
73
|
+
if (success) {
|
|
74
|
+
rawEvent.preventDefault();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function completeAnnotationsDrag(state, session) {
|
|
78
|
+
if (session.type === ANNOTATIONS_DRAW_DRAG_TYPE) {
|
|
79
|
+
const gesture = state.activeDrawGesture;
|
|
80
|
+
state.activeDrawGesture = null;
|
|
81
|
+
state.activeDrawPreviewTarget = null;
|
|
82
|
+
if (!gesture)
|
|
83
|
+
return;
|
|
84
|
+
if (session.targetSquare === null)
|
|
85
|
+
return;
|
|
86
|
+
if (gesture.sourceSquare === session.targetSquare) {
|
|
87
|
+
commitCircleToggle(state, gesture.sourceSquare, gesture.color);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
commitArrowToggle(state, gesture.sourceSquare, session.targetSquare, gesture.color);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (session.type !== ANNOTATIONS_IDLE_CLEAR_DRAG_TYPE)
|
|
95
|
+
return;
|
|
96
|
+
if (session.targetSquare === null)
|
|
97
|
+
return;
|
|
98
|
+
if (!hasCommittedAnnotations(state))
|
|
99
|
+
return;
|
|
100
|
+
clearCommittedAnnotations(state);
|
|
101
|
+
markCommittedDirtyAndRequestRender(state);
|
|
102
|
+
}
|
|
103
|
+
export function cancelAnnotationsDrag(state, session) {
|
|
104
|
+
if (session.type === ANNOTATIONS_DRAW_DRAG_TYPE) {
|
|
105
|
+
state.activeDrawGesture = null;
|
|
106
|
+
state.activeDrawPreviewTarget = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function commitCircleToggle(state, square, color) {
|
|
110
|
+
const existing = state.annotations.circles.get(square);
|
|
111
|
+
if (existing && existing.color === color) {
|
|
112
|
+
state.annotations.circles.delete(square);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
state.annotations.circles.set(square, { key: square, square, color });
|
|
116
|
+
}
|
|
117
|
+
markCommittedDirtyAndRequestRender(state);
|
|
118
|
+
}
|
|
119
|
+
function commitArrowToggle(state, from, to, color) {
|
|
120
|
+
const key = arrowAnnotationKeyNormalized(from, to);
|
|
121
|
+
const existing = state.annotations.arrows.get(key);
|
|
122
|
+
if (existing && existing.color === color) {
|
|
123
|
+
state.annotations.arrows.delete(key);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
state.annotations.arrows.set(key, { key, from, to, color });
|
|
127
|
+
}
|
|
128
|
+
markCommittedDirtyAndRequestRender(state);
|
|
129
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function markDirtyAndRequestRender(state, layers) {
|
|
2
|
+
state.runtimeSurface.invalidation.markDirty(layers);
|
|
3
|
+
state.runtimeSurface.commands.requestRender({ state: true });
|
|
4
|
+
}
|
|
5
|
+
export function markCommittedDirtyAndRequestRender(state) {
|
|
6
|
+
markDirtyAndRequestRender(state, 1 /* DirtyLayer.COMMITTED */);
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SquareString } from '../../../state/board/types/input.js';
|
|
2
|
+
import type { Square } from '../../../state/board/types/internal.js';
|
|
3
|
+
import type { AnnotationsConfig, ArrowAnnotation, ArrowAnnotationKey, CircleAnnotation, CircleAnnotationKey } from './types/internal.js';
|
|
4
|
+
import type { AnnotationsStateInternalAnnotations } from './types/main.js';
|
|
5
|
+
import type { AnnotationsInitOptionsAnnotations, AnnotationsInitOptionsConfig, ArrowAnnotationPublic, CircleAnnotationPublic } from './types/public.js';
|
|
6
|
+
export declare function normalizeAnnotationsConfig(input?: AnnotationsInitOptionsConfig): AnnotationsConfig;
|
|
7
|
+
export declare function circleAnnotationKey(square: SquareString): CircleAnnotationKey;
|
|
8
|
+
export declare function normalizeCircleAnnotation(pub: CircleAnnotationPublic): CircleAnnotation;
|
|
9
|
+
export declare function arrowAnnotationKeyNormalized(from: Square, to: Square): ArrowAnnotationKey;
|
|
10
|
+
export declare function arrowAnnotationKey(from: SquareString, to: SquareString): ArrowAnnotationKey;
|
|
11
|
+
export declare function normalizeArrowAnnotation(pub: ArrowAnnotationPublic): ArrowAnnotation;
|
|
12
|
+
export declare function normalizeInitialAnnotations(input?: AnnotationsInitOptionsAnnotations): AnnotationsStateInternalAnnotations;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { cloneDeep, toMerged } from 'es-toolkit';
|
|
2
|
+
import { normalizeSquare } from '../../../state/board/normalize.js';
|
|
3
|
+
import { DEFAULT_CONFIG } from './constants.js';
|
|
4
|
+
export function normalizeAnnotationsConfig(input) {
|
|
5
|
+
if (!input) {
|
|
6
|
+
return cloneDeep(DEFAULT_CONFIG);
|
|
7
|
+
}
|
|
8
|
+
return toMerged(DEFAULT_CONFIG, input);
|
|
9
|
+
}
|
|
10
|
+
export function circleAnnotationKey(square) {
|
|
11
|
+
return normalizeSquare(square);
|
|
12
|
+
}
|
|
13
|
+
export function normalizeCircleAnnotation(pub) {
|
|
14
|
+
const square = normalizeSquare(pub.square);
|
|
15
|
+
return {
|
|
16
|
+
key: square,
|
|
17
|
+
square,
|
|
18
|
+
color: pub.color
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function arrowAnnotationKeyNormalized(from, to) {
|
|
22
|
+
if (from === to) {
|
|
23
|
+
throw new Error("Invalid arrow: 'from' and 'to' must be different squares");
|
|
24
|
+
}
|
|
25
|
+
return from * 64 + to;
|
|
26
|
+
}
|
|
27
|
+
export function arrowAnnotationKey(from, to) {
|
|
28
|
+
const fromKey = normalizeSquare(from);
|
|
29
|
+
const toKey = normalizeSquare(to);
|
|
30
|
+
return arrowAnnotationKeyNormalized(fromKey, toKey);
|
|
31
|
+
}
|
|
32
|
+
export function normalizeArrowAnnotation(pub) {
|
|
33
|
+
const from = normalizeSquare(pub.from);
|
|
34
|
+
const to = normalizeSquare(pub.to);
|
|
35
|
+
const key = arrowAnnotationKeyNormalized(from, to);
|
|
36
|
+
return { key, from, to, color: pub.color };
|
|
37
|
+
}
|
|
38
|
+
export function normalizeInitialAnnotations(input) {
|
|
39
|
+
const circles = new Map();
|
|
40
|
+
const arrows = new Map();
|
|
41
|
+
if (input?.circles) {
|
|
42
|
+
for (const pub of input.circles) {
|
|
43
|
+
const circle = normalizeCircleAnnotation(pub);
|
|
44
|
+
circles.set(circle.key, circle);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (input?.arrows) {
|
|
48
|
+
for (const pub of input.arrows) {
|
|
49
|
+
const arrow = normalizeArrowAnnotation(pub);
|
|
50
|
+
arrows.set(arrow.key, arrow);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { circles, arrows };
|
|
54
|
+
}
|