@mirasen/chessboard 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +7 -1
  3. package/assets/watermark/mirasen.svg +10 -0
  4. package/dist/animation/render/fade.d.ts +2 -3
  5. package/dist/animation/render/fade.js +6 -6
  6. package/dist/animation/render/move.d.ts +2 -3
  7. package/dist/animation/render/move.js +6 -6
  8. package/dist/animation/render/plan.d.ts +3 -4
  9. package/dist/animation/render/plan.js +5 -5
  10. package/dist/animation/render/static.d.ts +2 -3
  11. package/dist/animation/render/static.js +4 -4
  12. package/dist/animation/render/types.d.ts +10 -4
  13. package/dist/extensions/build/index.d.ts +1 -2
  14. package/dist/extensions/build/index.js +1 -1
  15. package/dist/extensions/factory/main.js +11 -7
  16. package/dist/extensions/factory/runtime.js +24 -1
  17. package/dist/extensions/first-party/active-target/factory.js +18 -11
  18. package/dist/extensions/first-party/annotations/api.d.ts +16 -0
  19. package/dist/extensions/first-party/annotations/api.js +79 -0
  20. package/dist/extensions/first-party/annotations/committed.d.ts +3 -0
  21. package/dist/extensions/first-party/annotations/committed.js +11 -0
  22. package/dist/extensions/first-party/annotations/constants.d.ts +3 -0
  23. package/dist/extensions/first-party/annotations/constants.js +54 -0
  24. package/dist/extensions/first-party/annotations/denormalize.d.ts +4 -0
  25. package/dist/extensions/first-party/annotations/denormalize.js +22 -0
  26. package/dist/extensions/first-party/annotations/factory.d.ts +3 -0
  27. package/dist/extensions/first-party/annotations/factory.js +143 -0
  28. package/dist/extensions/first-party/annotations/interaction.d.ts +8 -0
  29. package/dist/extensions/first-party/annotations/interaction.js +129 -0
  30. package/dist/extensions/first-party/annotations/invalidation.d.ts +3 -0
  31. package/dist/extensions/first-party/annotations/invalidation.js +7 -0
  32. package/dist/extensions/first-party/annotations/normalize.d.ts +12 -0
  33. package/dist/extensions/first-party/annotations/normalize.js +54 -0
  34. package/dist/extensions/first-party/annotations/render/committed.d.ts +3 -0
  35. package/dist/extensions/first-party/annotations/render/committed.js +123 -0
  36. package/dist/extensions/first-party/annotations/render/helpers/arrows.d.ts +33 -0
  37. package/dist/extensions/first-party/annotations/render/helpers/arrows.js +93 -0
  38. package/dist/extensions/first-party/annotations/render/helpers/circles.d.ts +18 -0
  39. package/dist/extensions/first-party/annotations/render/helpers/circles.js +30 -0
  40. package/dist/extensions/first-party/annotations/render/preview.d.ts +3 -0
  41. package/dist/extensions/first-party/annotations/render/preview.js +96 -0
  42. package/dist/extensions/first-party/annotations/types/internal.d.ts +77 -0
  43. package/dist/extensions/first-party/annotations/types/internal.js +1 -0
  44. package/dist/extensions/first-party/annotations/types/main.d.ts +40 -0
  45. package/dist/extensions/first-party/annotations/types/main.js +6 -0
  46. package/dist/extensions/first-party/annotations/types/public.d.ts +48 -0
  47. package/dist/extensions/first-party/annotations/types/public.js +1 -0
  48. package/dist/extensions/first-party/annotations/update.d.ts +3 -0
  49. package/dist/extensions/first-party/annotations/update.js +45 -0
  50. package/dist/extensions/first-party/auto-promote/factory.js +6 -6
  51. package/dist/extensions/first-party/board-events/factory.js +6 -6
  52. package/dist/extensions/first-party/common/helpers.d.ts +2 -1
  53. package/dist/extensions/first-party/common/helpers.js +6 -5
  54. package/dist/extensions/first-party/common/types.d.ts +2 -0
  55. package/dist/extensions/first-party/last-move/factory.js +9 -9
  56. package/dist/extensions/first-party/legal-moves/factory.js +8 -8
  57. package/dist/extensions/first-party/main-renderer/animation/factory.d.ts +2 -2
  58. package/dist/extensions/first-party/main-renderer/animation/factory.js +4 -4
  59. package/dist/extensions/first-party/main-renderer/animation/render.d.ts +1 -1
  60. package/dist/extensions/first-party/main-renderer/animation/render.js +2 -2
  61. package/dist/extensions/first-party/main-renderer/animation/types.d.ts +3 -3
  62. package/dist/extensions/first-party/main-renderer/board/factory.js +2 -2
  63. package/dist/extensions/first-party/main-renderer/board/render.d.ts +1 -1
  64. package/dist/extensions/first-party/main-renderer/board/render.js +4 -4
  65. package/dist/extensions/first-party/main-renderer/board/types.d.ts +1 -1
  66. package/dist/extensions/first-party/main-renderer/coordinates/factory.js +2 -2
  67. package/dist/extensions/first-party/main-renderer/coordinates/render.d.ts +1 -1
  68. package/dist/extensions/first-party/main-renderer/coordinates/render.js +5 -5
  69. package/dist/extensions/first-party/main-renderer/coordinates/types.d.ts +1 -1
  70. package/dist/extensions/first-party/main-renderer/drag/factory.d.ts +2 -2
  71. package/dist/extensions/first-party/main-renderer/drag/factory.js +11 -8
  72. package/dist/extensions/first-party/main-renderer/drag/render.d.ts +1 -1
  73. package/dist/extensions/first-party/main-renderer/drag/render.js +7 -6
  74. package/dist/extensions/first-party/main-renderer/drag/types.d.ts +6 -5
  75. package/dist/extensions/first-party/main-renderer/drag/update.js +2 -2
  76. package/dist/extensions/first-party/main-renderer/factory.js +9 -5
  77. package/dist/extensions/first-party/main-renderer/piece-symbols.d.ts +19 -0
  78. package/dist/extensions/first-party/main-renderer/piece-symbols.js +45 -0
  79. package/dist/extensions/first-party/main-renderer/pieces/factory.d.ts +2 -2
  80. package/dist/extensions/first-party/main-renderer/pieces/factory.js +4 -4
  81. package/dist/extensions/first-party/main-renderer/pieces/render.d.ts +1 -1
  82. package/dist/extensions/first-party/main-renderer/pieces/render.js +8 -8
  83. package/dist/extensions/first-party/main-renderer/pieces/types.d.ts +4 -4
  84. package/dist/extensions/first-party/main-renderer/types/extension.d.ts +1 -1
  85. package/dist/extensions/first-party/main-renderer/types/extension.js +8 -1
  86. package/dist/extensions/first-party/main-renderer/types/instance.d.ts +2 -0
  87. package/dist/extensions/first-party/promotion/factory.js +10 -10
  88. package/dist/extensions/first-party/selected-square/factory.js +8 -8
  89. package/dist/extensions/first-party/watermark/factory.d.ts +2 -0
  90. package/dist/extensions/first-party/watermark/factory.js +82 -0
  91. package/dist/extensions/first-party/watermark/types.d.ts +13 -0
  92. package/dist/extensions/first-party/watermark/types.js +2 -0
  93. package/dist/extensions/types/basic/events.d.ts +32 -3
  94. package/dist/extensions/types/basic/events.js +2 -1
  95. package/dist/extensions/types/basic/mount.d.ts +5 -2
  96. package/dist/extensions/types/basic/mount.js +0 -2
  97. package/dist/extensions/types/basic/transient-visuals.d.ts +1 -1
  98. package/dist/extensions/types/context/animation.d.ts +3 -3
  99. package/dist/extensions/types/context/events.d.ts +2 -1
  100. package/dist/extensions/types/context/update.d.ts +6 -7
  101. package/dist/extensions/types/extension.d.ts +3 -0
  102. package/dist/extensions/types/main.d.ts +1 -0
  103. package/dist/extensions/types/surface/commands.d.ts +1 -1
  104. package/dist/extensions/types/surface/main.d.ts +6 -4
  105. package/dist/extensions/types/wrapper.d.ts +5 -1
  106. package/dist/extensions/types/wrapper.js +10 -2
  107. package/dist/extensions/update.js +6 -10
  108. package/dist/index.d.ts +1 -1
  109. package/dist/render/mount.js +3 -3
  110. package/dist/render/rendering/state.js +2 -2
  111. package/dist/render/svg/factory.js +40 -25
  112. package/dist/render/svg/helpers.d.ts +8 -4
  113. package/dist/render/svg/helpers.js +27 -12
  114. package/dist/render/svg/ids.d.ts +6 -0
  115. package/dist/render/svg/ids.js +11 -0
  116. package/dist/render/types.d.ts +4 -3
  117. package/dist/render/types.js +2 -1
  118. package/dist/runtime/factory/input.d.ts +3 -1
  119. package/dist/runtime/factory/input.js +11 -2
  120. package/dist/runtime/factory/main.js +10 -4
  121. package/dist/runtime/input/adapter/event.js +2 -2
  122. package/dist/runtime/input/adapter/pointer.d.ts +2 -2
  123. package/dist/runtime/input/controller/factory.d.ts +1 -1
  124. package/dist/runtime/input/controller/factory.js +35 -15
  125. package/dist/runtime/input/controller/helpers.d.ts +1 -1
  126. package/dist/runtime/input/controller/interaction.d.ts +3 -0
  127. package/dist/runtime/input/controller/interaction.js +14 -0
  128. package/dist/runtime/input/controller/pointer.d.ts +6 -6
  129. package/dist/runtime/input/controller/pointer.js +53 -27
  130. package/dist/runtime/input/controller/transient-visuals.d.ts +2 -3
  131. package/dist/runtime/input/controller/types.d.ts +6 -5
  132. package/dist/runtime/types/main.d.ts +1 -1
  133. package/dist/wrapper/factory.js +2 -7
  134. package/dist/wrapper/types.d.ts +3 -11
  135. package/package.json +1 -3
@@ -0,0 +1,30 @@
1
+ import { createSvgElement, updateSvgElementAttributes } from '../../../../../render/svg/helpers.js';
2
+ function computeCircleAttributes(params) {
3
+ const { square, color, radius, strokeWidth, opacity, geometry } = params;
4
+ const squareSize = geometry.squareSize;
5
+ const rect = geometry.getSquareRect(square);
6
+ return {
7
+ cx: (rect.x + rect.width / 2).toString(),
8
+ cy: (rect.y + rect.height / 2).toString(),
9
+ r: (squareSize * radius).toString(),
10
+ fill: 'none',
11
+ stroke: color,
12
+ 'stroke-width': (squareSize * strokeWidth).toString(),
13
+ opacity: opacity.toString()
14
+ };
15
+ }
16
+ export function createAnnotationCircleSvg(params) {
17
+ const attributes = computeCircleAttributes(params);
18
+ const circle = createSvgElement(params.parent, 'circle', {
19
+ 'data-chessboard-id': params.dataId,
20
+ ...attributes
21
+ });
22
+ return { circle };
23
+ }
24
+ export function updateAnnotationCircleSvg(rendered, params) {
25
+ const attributes = computeCircleAttributes(params);
26
+ updateSvgElementAttributes(rendered.circle, attributes);
27
+ }
28
+ export function removeAnnotationCircleSvg(rendered) {
29
+ rendered.circle.remove();
30
+ }
@@ -0,0 +1,3 @@
1
+ import type { SceneRenderGeometry } from '../../../../layout/geometry/types.js';
2
+ import type { AnnotationsStateInternal } from '../types/main.js';
3
+ export declare function renderPreviewAnnotations(state: AnnotationsStateInternal, geometry: SceneRenderGeometry): void;
@@ -0,0 +1,96 @@
1
+ import assert from '@ktarmyshov/assert';
2
+ import { VISUAL_CONFIG } from '../constants.js';
3
+ import { arrowAnnotationKeyNormalized } from '../normalize.js';
4
+ import { createAnnotationArrowSvg, removeAnnotationArrowSvg, updateAnnotationArrowSvg } from './helpers/arrows.js';
5
+ import { createAnnotationCircleSvg, removeAnnotationCircleSvg, updateAnnotationCircleSvg } from './helpers/circles.js';
6
+ export function renderPreviewAnnotations(state, geometry) {
7
+ assert(state.slotRoots, 'Expected slotRoots to be initialized before rendering preview');
8
+ const gesture = state.activeDrawGesture;
9
+ const target = state.activeDrawPreviewTarget;
10
+ // No preview needed: clear any existing preview DOM
11
+ if (gesture === null || target === null) {
12
+ clearPreviewCircle(state);
13
+ clearPreviewArrow(state);
14
+ return;
15
+ }
16
+ const source = gesture.sourceSquare;
17
+ const color = gesture.color;
18
+ if (target === source) {
19
+ // Circle preview
20
+ clearPreviewArrow(state);
21
+ renderPreviewCircle(state, geometry, source, color);
22
+ }
23
+ else {
24
+ // Arrow preview
25
+ clearPreviewCircle(state);
26
+ renderPreviewArrowSvg(state, geometry, source, target, color);
27
+ }
28
+ }
29
+ function renderPreviewCircle(state, geometry, square, color) {
30
+ const { previewAdd, previewRemoveOpacity } = VISUAL_CONFIG.circle;
31
+ // Determine add vs remove style
32
+ const existingCircle = state.annotations.circles.get(square);
33
+ const isRemove = existingCircle !== undefined && existingCircle.color === color;
34
+ const opacity = isRemove ? previewRemoveOpacity : previewAdd.opacity;
35
+ assert(state.slotRoots, 'Expected slotRoots to be initialized before rendering preview');
36
+ const params = {
37
+ parent: state.slotRoots.drag,
38
+ dataId: 'annotation-circle-preview',
39
+ square,
40
+ color,
41
+ radius: previewAdd.radius,
42
+ strokeWidth: previewAdd.strokeWidth,
43
+ opacity,
44
+ geometry
45
+ };
46
+ if (state.previewSvg.circle) {
47
+ updateAnnotationCircleSvg(state.previewSvg.circle, params);
48
+ }
49
+ else {
50
+ state.previewSvg.circle = createAnnotationCircleSvg(params);
51
+ }
52
+ }
53
+ function renderPreviewArrowSvg(state, geometry, from, to, color) {
54
+ const { committed, previewAdd, previewRemoveOpacity } = VISUAL_CONFIG.arrow;
55
+ // Determine add vs remove style
56
+ const arrowKey = arrowAnnotationKeyNormalized(from, to);
57
+ const existingArrow = state.annotations.arrows.get(arrowKey);
58
+ const isRemove = existingArrow !== undefined && existingArrow.color === color;
59
+ const visual = isRemove ? committed : previewAdd;
60
+ const opacity = isRemove ? previewRemoveOpacity : previewAdd.opacity;
61
+ const markerId = state.svgIds.makeId('annotations', 'arrowhead-preview');
62
+ const markerHref = `url(${state.svgIds.makeHref('annotations', 'arrowhead-preview')})`;
63
+ const params = {
64
+ defsRoot: state.slotRoots.defs,
65
+ visualRoot: state.slotRoots.drag,
66
+ markerDataId: 'annotation-arrowhead-preview',
67
+ markerPathDataId: 'annotation-arrowhead-path-preview',
68
+ lineDataId: 'annotation-arrow-preview',
69
+ markerId,
70
+ markerHref,
71
+ from,
72
+ to,
73
+ color,
74
+ opacity,
75
+ visual,
76
+ geometry
77
+ };
78
+ if (state.previewSvg.arrow) {
79
+ updateAnnotationArrowSvg(state.previewSvg.arrow, params);
80
+ }
81
+ else {
82
+ state.previewSvg.arrow = createAnnotationArrowSvg(params);
83
+ }
84
+ }
85
+ function clearPreviewCircle(state) {
86
+ if (state.previewSvg.circle) {
87
+ removeAnnotationCircleSvg(state.previewSvg.circle);
88
+ state.previewSvg.circle = null;
89
+ }
90
+ }
91
+ function clearPreviewArrow(state) {
92
+ if (state.previewSvg.arrow) {
93
+ removeAnnotationArrowSvg(state.previewSvg.arrow);
94
+ state.previewSvg.arrow = null;
95
+ }
96
+ }
@@ -0,0 +1,77 @@
1
+ import type { Square } from '../../../../state/board/types/internal.js';
2
+ import type { AnnotationsDrawModifier } from './public.js';
3
+ /** Annotation color as a CSS-compatible color string. */
4
+ export type AnnotationColor = string;
5
+ export type CircleAnnotationKey = Square;
6
+ export type ArrowAnnotationKey = number;
7
+ export interface CircleAnnotation {
8
+ readonly key: CircleAnnotationKey;
9
+ readonly square: Square;
10
+ readonly color: AnnotationColor;
11
+ }
12
+ export interface ArrowAnnotation {
13
+ readonly key: ArrowAnnotationKey;
14
+ readonly from: Square;
15
+ readonly to: Square;
16
+ readonly color: AnnotationColor;
17
+ }
18
+ export interface AnnotationModifierColorConfig {
19
+ readonly none: AnnotationColor;
20
+ readonly ctrl: AnnotationColor;
21
+ readonly shift: AnnotationColor;
22
+ readonly alt: AnnotationColor;
23
+ readonly meta: AnnotationColor;
24
+ }
25
+ export interface AnnotationsConfig {
26
+ clearOnCoreInteraction: boolean;
27
+ drawButton: number;
28
+ drawModifier: AnnotationsDrawModifier | null;
29
+ readonly colors: AnnotationModifierColorConfig;
30
+ }
31
+ export interface ActiveDrawGesture {
32
+ readonly sourceSquare: Square;
33
+ readonly color: AnnotationColor;
34
+ }
35
+ export interface VisualConfigCircleAnnotation {
36
+ strokeWidth: number;
37
+ radius: number;
38
+ opacity: number;
39
+ }
40
+ export interface VisualConfigArrowAnnotation {
41
+ strokeWidth: number;
42
+ startOffset: number;
43
+ endOffset: number;
44
+ opacity: number;
45
+ markerWidth: number;
46
+ markerHeight: number;
47
+ markerRefX: number;
48
+ markerRefY: number;
49
+ markerViewBox: string;
50
+ markerPathD: string;
51
+ }
52
+ export interface VisualConfigCircle {
53
+ readonly committed: VisualConfigCircleAnnotation;
54
+ readonly previewAdd: VisualConfigCircleAnnotation;
55
+ /**
56
+ * Remove preview reuses previewAdd definitions
57
+ * and overrides only opacity.
58
+ */
59
+ readonly previewRemoveOpacity: number;
60
+ }
61
+ export interface VisualConfigArrow {
62
+ readonly committed: VisualConfigArrowAnnotation;
63
+ readonly previewAdd: VisualConfigArrowAnnotation;
64
+ /**
65
+ * Remove preview reuses committed arrow definitions
66
+ * and overrides only opacity.
67
+ */
68
+ readonly previewRemoveOpacity: number;
69
+ }
70
+ export interface VisualConfig {
71
+ readonly circle: VisualConfigCircle;
72
+ readonly arrow: VisualConfigArrow;
73
+ }
74
+ export declare const enum DirtyLayer {
75
+ COMMITTED = 1,
76
+ PREVIEW = 2
77
+ }
@@ -0,0 +1,40 @@
1
+ import type { Square } from '../../../../state/board/types/internal.js';
2
+ import type { ExtensionDefinition, ExtensionInstance } from '../../../types/extension.js';
3
+ import type { ExtensionRuntimeSurface } from '../../../types/surface/main.js';
4
+ import type { ExtensionInternalBase } from '../../common/types.js';
5
+ import type { ActiveDrawGesture, AnnotationsConfig, ArrowAnnotation, ArrowAnnotationKey, CircleAnnotation, CircleAnnotationKey } from './internal.js';
6
+ import type { AnnotationsPublicAPI } from './public.js';
7
+ export declare const EXTENSION_SLOTS: readonly ["defs", "overPieces", "drag"];
8
+ export type ExtensionSlotsType = typeof EXTENSION_SLOTS;
9
+ export declare const EXTENSION_ID: "annotations";
10
+ export type AnnotationsDefinition = ExtensionDefinition<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, AnnotationsPublicAPI>;
11
+ export type AnnotationsInstance = ExtensionInstance<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, AnnotationsPublicAPI>;
12
+ export interface RenderedAnnotationCircleSvg {
13
+ readonly circle: SVGCircleElement;
14
+ }
15
+ export interface RenderedAnnotationArrowSvg {
16
+ readonly line: SVGLineElement;
17
+ readonly marker: SVGMarkerElement;
18
+ readonly markerPath: SVGPathElement;
19
+ }
20
+ export interface AnnotationsStateInternalSvg {
21
+ readonly svgCircles: Map<CircleAnnotationKey, RenderedAnnotationCircleSvg>;
22
+ readonly svgArrows: Map<ArrowAnnotationKey, RenderedAnnotationArrowSvg>;
23
+ }
24
+ export interface AnnotationsStateInternalAnnotations {
25
+ readonly circles: Map<CircleAnnotationKey, CircleAnnotation>;
26
+ readonly arrows: Map<ArrowAnnotationKey, ArrowAnnotation>;
27
+ }
28
+ export interface AnnotationsStateInternalPreviewSvg {
29
+ circle: RenderedAnnotationCircleSvg | null;
30
+ arrow: RenderedAnnotationArrowSvg | null;
31
+ }
32
+ export interface AnnotationsStateInternal extends ExtensionInternalBase<ExtensionSlotsType> {
33
+ readonly runtimeSurface: ExtensionRuntimeSurface;
34
+ readonly svg: AnnotationsStateInternalSvg;
35
+ readonly annotations: AnnotationsStateInternalAnnotations;
36
+ readonly config: AnnotationsConfig;
37
+ activeDrawGesture: ActiveDrawGesture | null;
38
+ activeDrawPreviewTarget: Square | null;
39
+ readonly previewSvg: AnnotationsStateInternalPreviewSvg;
40
+ }
@@ -0,0 +1,6 @@
1
+ export const EXTENSION_SLOTS = [
2
+ 'defs',
3
+ 'overPieces',
4
+ 'drag'
5
+ ];
6
+ export const EXTENSION_ID = 'annotations';
@@ -0,0 +1,48 @@
1
+ import type { SquareString } from '../../../../state/board/types/input.js';
2
+ /** The annotation color resolved from user input modifiers. */
3
+ export type AnnotationColorPublic = string;
4
+ export interface CircleAnnotationPublic {
5
+ readonly square: SquareString;
6
+ readonly color: AnnotationColorPublic;
7
+ }
8
+ export interface ArrowAnnotationPublic {
9
+ readonly from: SquareString;
10
+ readonly to: SquareString;
11
+ readonly color: AnnotationColorPublic;
12
+ }
13
+ export interface AnnotationsInitOptionsConfigModifierColor {
14
+ none?: AnnotationColorPublic;
15
+ ctrl?: AnnotationColorPublic;
16
+ shift?: AnnotationColorPublic;
17
+ alt?: AnnotationColorPublic;
18
+ meta?: AnnotationColorPublic;
19
+ }
20
+ export type AnnotationsDrawModifier = Exclude<keyof AnnotationsInitOptionsConfigModifierColor, 'none'>;
21
+ export interface AnnotationsInitOptionsConfig {
22
+ clearOnCoreInteraction?: boolean;
23
+ drawButton?: number;
24
+ drawModifier?: AnnotationsDrawModifier | null;
25
+ colors?: AnnotationsInitOptionsConfigModifierColor;
26
+ }
27
+ export interface AnnotationsInitOptionsAnnotations {
28
+ circles?: CircleAnnotationPublic[];
29
+ arrows?: ArrowAnnotationPublic[];
30
+ }
31
+ export interface AnnotationsInitOptions {
32
+ config?: AnnotationsInitOptionsConfig;
33
+ annotations?: AnnotationsInitOptionsAnnotations;
34
+ }
35
+ export type CircleAnnotationValuePublic = Omit<CircleAnnotationPublic, 'square'>;
36
+ export type ArrowAnnotationValuePublic = Omit<ArrowAnnotationPublic, 'from' | 'to'>;
37
+ export interface AnnotationsPublicAPI {
38
+ getCircles(): CircleAnnotationPublic[];
39
+ getArrows(): ArrowAnnotationPublic[];
40
+ setCircles(circles: CircleAnnotationPublic[]): void;
41
+ setArrows(arrows: ArrowAnnotationPublic[]): void;
42
+ circle(square: SquareString, annotation: CircleAnnotationValuePublic | null): void;
43
+ arrow(from: SquareString, to: SquareString, annotation: ArrowAnnotationValuePublic | null): void;
44
+ clear(): void;
45
+ clearOnCoreInteraction: boolean;
46
+ drawButton: number;
47
+ drawModifier: AnnotationsDrawModifier | null;
48
+ }
@@ -0,0 +1,3 @@
1
+ import type { ExtensionUpdateContext } from '../../types/context/update.js';
2
+ import type { AnnotationsStateInternal } from './types/main.js';
3
+ export declare function annotationsOnUpdate(state: AnnotationsStateInternal, context: ExtensionUpdateContext): void;
@@ -0,0 +1,45 @@
1
+ import { isUpdateContextRenderable } from '../../types/context/update.js';
2
+ import { clearCommittedAnnotations, hasCommittedAnnotations } from './committed.js';
3
+ import { EXTENSION_ID } from './types/main.js';
4
+ export function annotationsOnUpdate(state, context) {
5
+ if (state.config.clearOnCoreInteraction &&
6
+ hasCommittedAnnotations(state) &&
7
+ context.mutation.hasMutation({
8
+ causes: ['runtime.interaction.completeCoreDragTo']
9
+ })) {
10
+ clearCommittedAnnotations(state);
11
+ context.invalidation.markDirty(1 /* DirtyLayer.COMMITTED */);
12
+ }
13
+ if (context.mutation.hasMutation({
14
+ causes: ['layout.refreshGeometry']
15
+ }) &&
16
+ isUpdateContextRenderable(context)) {
17
+ context.invalidation.markDirty(1 /* DirtyLayer.COMMITTED */);
18
+ if (state.activeDrawPreviewTarget !== null ||
19
+ state.previewSvg.circle !== null ||
20
+ state.previewSvg.arrow !== null) {
21
+ context.invalidation.markDirty(2 /* DirtyLayer.PREVIEW */);
22
+ }
23
+ }
24
+ // Preview target tracking from ext:draw drag session
25
+ let nextPreviewTarget = null;
26
+ if (state.activeDrawGesture !== null) {
27
+ const dragSession = context.currentFrame.state.interaction.dragSession;
28
+ if (dragSession &&
29
+ dragSession.type === 'ext:draw' &&
30
+ 'owner' in dragSession &&
31
+ dragSession.owner === EXTENSION_ID) {
32
+ nextPreviewTarget = dragSession.targetSquare;
33
+ }
34
+ }
35
+ if (nextPreviewTarget !== state.activeDrawPreviewTarget) {
36
+ state.activeDrawPreviewTarget = nextPreviewTarget;
37
+ context.invalidation.markDirty(2 /* DirtyLayer.PREVIEW */);
38
+ context.invalidation.markDirty(1 /* DirtyLayer.COMMITTED */);
39
+ }
40
+ else if (nextPreviewTarget === null &&
41
+ (state.previewSvg.circle !== null || state.previewSvg.arrow !== null)) {
42
+ context.invalidation.markDirty(2 /* DirtyLayer.PREVIEW */);
43
+ context.invalidation.markDirty(1 /* DirtyLayer.COMMITTED */);
44
+ }
45
+ }
@@ -4,14 +4,14 @@ export function createAutoPromote() {
4
4
  return {
5
5
  id: EXTENSION_ID,
6
6
  slots: EXTENSION_SLOTS,
7
- createInstance() {
8
- return createAutoPromoteInstance();
7
+ createInstance(options) {
8
+ return createAutoPromoteInstance(options);
9
9
  }
10
10
  };
11
11
  }
12
- function createAutoPromoteInternal() {
12
+ function createAutoPromoteInternal(options) {
13
13
  return {
14
- ...extensionCreateInternalBase(),
14
+ ...extensionCreateInternalBase(options),
15
15
  toQueen: false
16
16
  };
17
17
  }
@@ -25,8 +25,8 @@ function createAutoPromoteInstancePublic(state) {
25
25
  }
26
26
  };
27
27
  }
28
- function createAutoPromoteInstance() {
29
- const internalState = createAutoPromoteInternal();
28
+ function createAutoPromoteInstance(options) {
29
+ const internalState = createAutoPromoteInternal(options);
30
30
  const publicInterface = createAutoPromoteInstancePublic(internalState);
31
31
  return {
32
32
  id: EXTENSION_ID,
@@ -5,14 +5,14 @@ export function createBoardEvents() {
5
5
  return {
6
6
  id: EXTENSION_ID,
7
7
  slots: EXTENSION_SLOTS,
8
- createInstance() {
9
- return createBoardEventsInstance();
8
+ createInstance(options) {
9
+ return createBoardEventsInstance(options);
10
10
  }
11
11
  };
12
12
  }
13
- function createBoardEventsInternal() {
13
+ function createBoardEventsInternal(options) {
14
14
  return {
15
- ...extensionCreateInternalBase(),
15
+ ...extensionCreateInternalBase(options),
16
16
  onUIMove: null,
17
17
  onRawUpdate: null
18
18
  };
@@ -27,8 +27,8 @@ function createBoardEventsInstancePublic(state) {
27
27
  }
28
28
  };
29
29
  }
30
- function createBoardEventsInstance() {
31
- const internalState = createBoardEventsInternal();
30
+ function createBoardEventsInstance(options) {
31
+ const internalState = createBoardEventsInternal(options);
32
32
  const publicInterface = createBoardEventsInstancePublic(internalState);
33
33
  return {
34
34
  id: EXTENSION_ID,
@@ -1,6 +1,7 @@
1
1
  import { ExtensionSlotName } from '../../types/basic/mount.js';
2
+ import type { ExtensionCreateInstanceOptions } from '../../types/extension.js';
2
3
  import { ExtensionInternalBase } from './types.js';
3
- export declare function extensionCreateInternalBase<TSlots extends readonly ExtensionSlotName[]>(): ExtensionInternalBase<TSlots>;
4
+ export declare function extensionCreateInternalBase<TSlots extends readonly ExtensionSlotName[]>(options: ExtensionCreateInstanceOptions): ExtensionInternalBase<TSlots>;
4
5
  export declare function extensionIsMountedBase<TSlots extends readonly ExtensionSlotName[]>(state: ExtensionInternalBase<TSlots>): boolean;
5
6
  export declare function extensionIsDestroyedBase<TSlots extends readonly ExtensionSlotName[]>(state: ExtensionInternalBase<TSlots>): boolean;
6
7
  export declare function extensionMountBase<TSlots extends readonly ExtensionSlotName[]>(state: ExtensionInternalBase<TSlots>, slotRoots: NonNullable<ExtensionInternalBase<TSlots>['slotRoots']>): void;
@@ -1,9 +1,10 @@
1
1
  import assert from '@ktarmyshov/assert';
2
- import { clearElementChildren } from '../../../render/svg/helpers.js';
3
- export function extensionCreateInternalBase() {
2
+ import { clearSvgElementChildren } from '../../../render/svg/helpers.js';
3
+ export function extensionCreateInternalBase(options) {
4
4
  return {
5
5
  slotRoots: null,
6
- destroyed: false
6
+ destroyed: false,
7
+ svgIds: options.svgIds
7
8
  };
8
9
  }
9
10
  export function extensionIsMountedBase(state) {
@@ -19,8 +20,8 @@ export function extensionMountBase(state, slotRoots) {
19
20
  }
20
21
  export function extensionUnmountBase(state) {
21
22
  assert(extensionIsMountedBase(state), 'Extension is not mounted');
22
- for (const slotRoot of Object.values(state.slotRoots ?? {})) {
23
- clearElementChildren(slotRoot);
23
+ for (const [, slotRoot] of Object.entries(state.slotRoots ?? {})) {
24
+ clearSvgElementChildren(slotRoot);
24
25
  }
25
26
  state.slotRoots = null;
26
27
  }
@@ -1,7 +1,9 @@
1
+ import type { SvgIdResolver } from '../../../render/svg/ids.js';
1
2
  import { ExtensionSlotName, ExtensionSlotSvgRoots } from '../../types/basic/mount.js';
2
3
  export interface ExtensionInternalBase<TSlots extends readonly ExtensionSlotName[]> {
3
4
  slotRoots: ExtensionSlotSvgRoots<TSlots> | null;
4
5
  destroyed: boolean;
6
+ readonly svgIds: SvgIdResolver;
5
7
  }
6
8
  export interface OpaqueColor {
7
9
  color: string;
@@ -1,6 +1,6 @@
1
1
  import assert from '@ktarmyshov/assert';
2
2
  import { toMerged } from 'es-toolkit';
3
- import { createSvgElement, updateElementAttributes } from '../../../render/svg/helpers.js';
3
+ import { createSvgElement, updateSvgElementAttributes } from '../../../render/svg/helpers.js';
4
4
  import { isUpdateContextRenderable } from '../../types/context/update.js';
5
5
  import { extensionCreateInternalBase, extensionDestroyBase, extensionMountBase, extensionUnmountBase } from '../common/helpers.js';
6
6
  import { DEFAULT_CONFIG, EXTENSION_ID, EXTENSION_SLOTS } from './types.js';
@@ -9,14 +9,14 @@ export function createLastMove(config = {}) {
9
9
  return {
10
10
  id: EXTENSION_ID,
11
11
  slots: EXTENSION_SLOTS,
12
- createInstance() {
13
- return createLastMoveInstance(mergedConfig);
12
+ createInstance(options) {
13
+ return createLastMoveInstance(options, mergedConfig);
14
14
  }
15
15
  };
16
16
  }
17
- function createLastMoveInternal(config) {
17
+ function createLastMoveInternal(options, config) {
18
18
  return {
19
- ...extensionCreateInternalBase(),
19
+ ...extensionCreateInternalBase(options),
20
20
  svgRectFrom: null,
21
21
  svgRectTo: null,
22
22
  config
@@ -26,8 +26,8 @@ function extensionClean(state) {
26
26
  state.svgRectFrom = null;
27
27
  state.svgRectTo = null;
28
28
  }
29
- function createLastMoveInstance(config) {
30
- const internalState = createLastMoveInternal(config);
29
+ function createLastMoveInstance(options, config) {
30
+ const internalState = createLastMoveInternal(options, config);
31
31
  return {
32
32
  id: EXTENSION_ID,
33
33
  mount(env) {
@@ -89,9 +89,9 @@ function createLastMoveInstance(config) {
89
89
  });
90
90
  }
91
91
  else {
92
- updateElementAttributes(internalState.svgRectFrom, rectFromAttributes);
92
+ updateSvgElementAttributes(internalState.svgRectFrom, rectFromAttributes);
93
93
  assert(internalState.svgRectTo, 'svgRectTo should be available if svgRectFrom is available');
94
- updateElementAttributes(internalState.svgRectTo, rectToAttributes);
94
+ updateSvgElementAttributes(internalState.svgRectTo, rectToAttributes);
95
95
  }
96
96
  },
97
97
  unmount() {
@@ -1,6 +1,6 @@
1
1
  import assert from '@ktarmyshov/assert';
2
2
  import { toMerged } from 'es-toolkit';
3
- import { clearElementChildren, createSvgElement } from '../../../render/svg/helpers.js';
3
+ import { clearSvgElementChildren, createSvgElement } from '../../../render/svg/helpers.js';
4
4
  import { isNonEmptyPieceCode } from '../../../state/board/check.js';
5
5
  import { fromPieceCode } from '../../../state/board/piece.js';
6
6
  import { isUpdateContextRenderable } from '../../types/context/update.js';
@@ -11,14 +11,14 @@ export function createLegalMoves(config = {}) {
11
11
  return {
12
12
  id: EXTENSION_ID,
13
13
  slots: EXTENSION_SLOTS,
14
- createInstance() {
15
- return createLegalMovesInstance(mergedConfig);
14
+ createInstance(options) {
15
+ return createLegalMovesInstance(options, mergedConfig);
16
16
  }
17
17
  };
18
18
  }
19
- function createLegalMovesInternal(config) {
19
+ function createLegalMovesInternal(options, config) {
20
20
  return {
21
- ...extensionCreateInternalBase(),
21
+ ...extensionCreateInternalBase(options),
22
22
  svgCircles: [],
23
23
  config
24
24
  };
@@ -26,8 +26,8 @@ function createLegalMovesInternal(config) {
26
26
  function extensionClean(state) {
27
27
  state.svgCircles = [];
28
28
  }
29
- function createLegalMovesInstance(config) {
30
- const internalState = createLegalMovesInternal(config);
29
+ function createLegalMovesInstance(options, config) {
30
+ const internalState = createLegalMovesInternal(options, config);
31
31
  return {
32
32
  id: EXTENSION_ID,
33
33
  mount(env) {
@@ -47,7 +47,7 @@ function createLegalMovesInstance(config) {
47
47
  render(context) {
48
48
  assert(context.invalidation.dirtyLayers !== 0, 'Render should only be called when there are dirty layers');
49
49
  assert(internalState.slotRoots, 'Slot roots should be available when render is called');
50
- clearElementChildren(internalState.slotRoots.overPieces);
50
+ clearSvgElementChildren(internalState.slotRoots.overPieces);
51
51
  internalState.svgCircles = [];
52
52
  const interaction = context.currentFrame.state.interaction;
53
53
  const needsRender = interaction.movability.mode === 2 /* MovabilityModeCode.Strict */ &&
@@ -1,4 +1,4 @@
1
1
  import type { ExtensionRuntimeSurface } from '../../../types/surface/main.js';
2
- import type { PieceUrls } from '../types/internal.js';
2
+ import type { PieceSymbolResolver } from '../piece-symbols.js';
3
3
  import type { MainRendererAnimation } from './types.js';
4
- export declare function createMainRendererAnimation(config: PieceUrls, runtimeSurface: ExtensionRuntimeSurface): MainRendererAnimation;
4
+ export declare function createMainRendererAnimation(runtimeSurface: ExtensionRuntimeSurface, resolver: PieceSymbolResolver): MainRendererAnimation;
@@ -1,18 +1,18 @@
1
1
  import { cleanAnimationPlan } from '../../../../animation/render/plan.js';
2
2
  import { getAnimationSuppressedSquares, rendererAnimationClean, rendererAnimationPrepare, rendererAnimationRender } from './render.js';
3
3
  import { rendererAnimationOnUpdate } from './update.js';
4
- export function createMainRendererAnimation(config, runtimeSurface) {
4
+ export function createMainRendererAnimation(runtimeSurface, resolver) {
5
5
  const state = {
6
- config,
7
6
  runtimeSurface,
7
+ resolver,
8
8
  entries: new Map()
9
9
  };
10
10
  return {
11
11
  onUpdate(context) {
12
12
  rendererAnimationOnUpdate(state, context);
13
13
  },
14
- prepareAnimation(context, layer) {
15
- rendererAnimationPrepare(state, context, layer);
14
+ prepareAnimation(context, slot) {
15
+ rendererAnimationPrepare(state, context, slot);
16
16
  },
17
17
  renderAnimation(context) {
18
18
  rendererAnimationRender(state, context);
@@ -1,7 +1,7 @@
1
1
  import type { Square } from '../../../../state/board/types/internal.js';
2
2
  import type { ExtensionCleanAnimationContext, ExtensionPrepareAnimationContext, ExtensionRenderAnimationContext } from '../../../types/context/animation.js';
3
3
  import type { MainRendererAnimationInternal } from './types.js';
4
- export declare function rendererAnimationPrepare(state: MainRendererAnimationInternal, context: ExtensionPrepareAnimationContext, layer: SVGElement): void;
4
+ export declare function rendererAnimationPrepare(state: MainRendererAnimationInternal, context: ExtensionPrepareAnimationContext, slot: SVGGElement): void;
5
5
  export declare function rendererAnimationRender(state: MainRendererAnimationInternal, context: ExtensionRenderAnimationContext): void;
6
6
  export declare function rendererAnimationClean(state: MainRendererAnimationInternal, context: ExtensionCleanAnimationContext): void;
7
7
  export declare function getAnimationSuppressedSquares(state: MainRendererAnimationInternal): ReadonlySet<Square>;
@@ -1,10 +1,10 @@
1
1
  import { cleanAnimationPlan, prepareAnimationPlan, renderAnimationPlan } from '../../../../animation/render/plan.js';
2
2
  const EMPTY_SQUARES = new Set();
3
- export function rendererAnimationPrepare(state, context, layer) {
3
+ export function rendererAnimationPrepare(state, context, slot) {
4
4
  for (const session of context.submittedSessions) {
5
5
  const entry = state.entries.get(session.id);
6
6
  if (entry && entry.nodes === null) {
7
- entry.nodes = prepareAnimationPlan(entry.plan, context.currentFrame.layout.geometry, state.config, layer);
7
+ entry.nodes = prepareAnimationPlan(entry.plan, context.currentFrame.layout.geometry, state.resolver.getHref, slot);
8
8
  }
9
9
  }
10
10
  }
@@ -4,19 +4,19 @@ import { Square } from '../../../../state/board/types/internal.js';
4
4
  import { ExtensionCleanAnimationContext, ExtensionPrepareAnimationContext, ExtensionRenderAnimationContext } from '../../../types/context/animation.js';
5
5
  import { ExtensionUpdateContext } from '../../../types/context/update.js';
6
6
  import { ExtensionRuntimeSurface } from '../../../types/surface/main.js';
7
- import type { PieceUrls } from '../types/internal.js';
7
+ import type { PieceSymbolResolver } from '../piece-symbols.js';
8
8
  export interface MainRendererAnimationEntry {
9
9
  plan: AnimationPlan;
10
10
  nodes: PreparedNodeMap | null;
11
11
  }
12
12
  export interface MainRendererAnimationInternal {
13
- readonly config: PieceUrls;
14
13
  readonly runtimeSurface: ExtensionRuntimeSurface;
14
+ readonly resolver: PieceSymbolResolver;
15
15
  readonly entries: Map<number, MainRendererAnimationEntry>;
16
16
  }
17
17
  export interface MainRendererAnimation {
18
18
  onUpdate(context: ExtensionUpdateContext): void;
19
- prepareAnimation(context: ExtensionPrepareAnimationContext, layer: SVGElement): void;
19
+ prepareAnimation(context: ExtensionPrepareAnimationContext, slot: SVGGElement): void;
20
20
  renderAnimation(context: ExtensionRenderAnimationContext): void;
21
21
  cleanAnimation(context: ExtensionCleanAnimationContext): void;
22
22
  getSuppressedSquares(): ReadonlySet<Square>;