@mirasen/chessboard 0.1.1 → 1.0.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 (139) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +240 -45
  3. package/dist/animation/planner.d.ts +11 -6
  4. package/dist/animation/planner.js +164 -45
  5. package/dist/animation/render/fade.d.ts +2 -2
  6. package/dist/animation/render/fade.js +3 -3
  7. package/dist/animation/render/move.d.ts +3 -3
  8. package/dist/animation/render/move.js +5 -5
  9. package/dist/animation/render/plan.d.ts +3 -3
  10. package/dist/animation/render/static.d.ts +2 -2
  11. package/dist/animation/render/static.js +3 -3
  12. package/dist/animation/types.d.ts +14 -15
  13. package/dist/animation/types.js +1 -6
  14. package/dist/extensions/build/index.d.ts +21 -0
  15. package/dist/extensions/build/index.js +9 -0
  16. package/dist/extensions/factory/main.js +23 -2
  17. package/dist/extensions/factory/runtime.d.ts +2 -1
  18. package/dist/extensions/factory/runtime.js +48 -4
  19. package/dist/extensions/first-party/active-target/factory.js +9 -9
  20. package/dist/extensions/first-party/active-target/types.d.ts +2 -2
  21. package/dist/extensions/first-party/active-target/types.js +4 -1
  22. package/dist/extensions/first-party/auto-promote/factory.d.ts +2 -0
  23. package/dist/extensions/first-party/auto-promote/factory.js +51 -0
  24. package/dist/extensions/first-party/auto-promote/types.d.ts +12 -0
  25. package/dist/extensions/first-party/auto-promote/types.js +2 -0
  26. package/dist/extensions/first-party/board-events/factory.js +1 -16
  27. package/dist/extensions/first-party/board-events/types.d.ts +1 -4
  28. package/dist/extensions/first-party/common/helpers.d.ts +7 -7
  29. package/dist/extensions/first-party/common/helpers.js +11 -11
  30. package/dist/extensions/first-party/common/types.d.ts +2 -3
  31. package/dist/extensions/first-party/last-move/factory.js +10 -10
  32. package/dist/extensions/first-party/last-move/types.d.ts +2 -2
  33. package/dist/extensions/first-party/legal-moves/factory.js +5 -5
  34. package/dist/extensions/first-party/legal-moves/types.d.ts +2 -2
  35. package/dist/extensions/first-party/main-renderer/animation/render.js +1 -2
  36. package/dist/extensions/first-party/main-renderer/animation/update.js +9 -23
  37. package/dist/extensions/first-party/main-renderer/board/render.js +3 -3
  38. package/dist/extensions/first-party/main-renderer/board/update.js +5 -3
  39. package/dist/extensions/first-party/main-renderer/coordinates/render.js +4 -4
  40. package/dist/extensions/first-party/main-renderer/drag/render.js +1 -1
  41. package/dist/extensions/first-party/main-renderer/factory.js +4 -4
  42. package/dist/extensions/first-party/main-renderer/normalize.d.ts +2 -3
  43. package/dist/extensions/first-party/main-renderer/normalize.js +1 -1
  44. package/dist/extensions/first-party/main-renderer/pieces/render.js +5 -5
  45. package/dist/extensions/first-party/main-renderer/pieces/suppress.js +7 -2
  46. package/dist/extensions/first-party/main-renderer/types/extension.d.ts +1 -1
  47. package/dist/extensions/first-party/main-renderer/types/extension.js +1 -1
  48. package/dist/extensions/first-party/main-renderer/types/instance.d.ts +2 -2
  49. package/dist/extensions/first-party/promotion/factory.d.ts +3 -0
  50. package/dist/extensions/first-party/promotion/factory.js +219 -0
  51. package/dist/extensions/first-party/promotion/normalize.d.ts +3 -0
  52. package/dist/extensions/first-party/promotion/normalize.js +37 -0
  53. package/dist/extensions/first-party/promotion/types/input.d.ts +10 -0
  54. package/dist/extensions/first-party/promotion/types/internal.d.ts +12 -0
  55. package/dist/extensions/first-party/promotion/types/internal.js +22 -0
  56. package/dist/extensions/first-party/promotion/types/main.d.ts +24 -0
  57. package/dist/extensions/first-party/promotion/types/main.js +2 -0
  58. package/dist/extensions/first-party/selected-square/factory.js +7 -7
  59. package/dist/extensions/first-party/selected-square/types.d.ts +2 -2
  60. package/dist/extensions/index.d.ts +1 -8
  61. package/dist/extensions/index.js +1 -6
  62. package/dist/extensions/types/basic/events.d.ts +8 -31
  63. package/dist/extensions/types/basic/events.js +9 -5
  64. package/dist/extensions/types/basic/interaction.d.ts +21 -0
  65. package/dist/extensions/types/basic/transient-visuals.d.ts +2 -1
  66. package/dist/extensions/types/context/events.d.ts +5 -0
  67. package/dist/extensions/types/context/events.js +1 -0
  68. package/dist/extensions/types/context/ui-move.d.ts +3 -15
  69. package/dist/extensions/types/extension.d.ts +10 -8
  70. package/dist/extensions/types/main.d.ts +11 -6
  71. package/dist/extensions/types/surface/commands.d.ts +9 -0
  72. package/dist/extensions/types/surface/events.d.ts +2 -3
  73. package/dist/extensions/types/wrapper.d.ts +23 -22
  74. package/dist/extensions/types/wrapper.js +34 -6
  75. package/dist/extensions/update.d.ts +2 -2
  76. package/dist/extensions/update.js +1 -1
  77. package/dist/index.d.ts +1 -2
  78. package/dist/layout/factory.js +3 -3
  79. package/dist/layout/geometry/factory.d.ts +2 -11
  80. package/dist/layout/geometry/factory.js +16 -17
  81. package/dist/layout/geometry/helpers.d.ts +5 -0
  82. package/dist/layout/geometry/helpers.js +33 -0
  83. package/dist/layout/geometry/types.d.ts +13 -12
  84. package/dist/layout/helpers.d.ts +3 -4
  85. package/dist/layout/helpers.js +5 -5
  86. package/dist/layout/reducers.js +9 -8
  87. package/dist/layout/types.d.ts +5 -5
  88. package/dist/render/mount.js +2 -2
  89. package/dist/render/rendering/state.js +7 -7
  90. package/dist/runtime/factory/events.d.ts +3 -0
  91. package/dist/runtime/factory/events.js +18 -0
  92. package/dist/runtime/factory/helpers.js +12 -12
  93. package/dist/runtime/factory/input.js +17 -10
  94. package/dist/runtime/factory/main.js +44 -4
  95. package/dist/runtime/input/adapter/event.d.ts +3 -0
  96. package/dist/runtime/input/adapter/event.js +19 -0
  97. package/dist/runtime/input/adapter/factory.js +19 -38
  98. package/dist/runtime/input/adapter/helpers.d.ts +3 -5
  99. package/dist/runtime/input/adapter/helpers.js +60 -12
  100. package/dist/runtime/input/adapter/pointer.d.ts +6 -10
  101. package/dist/runtime/input/adapter/pointer.js +37 -70
  102. package/dist/runtime/input/adapter/types.d.ts +6 -3
  103. package/dist/runtime/input/adapter/types.js +6 -1
  104. package/dist/runtime/input/controller/factory.js +12 -11
  105. package/dist/runtime/input/controller/pointer.d.ts +5 -6
  106. package/dist/runtime/input/controller/pointer.js +36 -35
  107. package/dist/runtime/input/controller/transient-visuals.d.ts +2 -2
  108. package/dist/runtime/input/controller/transient-visuals.js +12 -5
  109. package/dist/runtime/input/controller/types.d.ts +5 -4
  110. package/dist/runtime/lifecycle.js +6 -6
  111. package/dist/runtime/mutation/interaction.js +1 -5
  112. package/dist/runtime/mutation/types.d.ts +10 -8
  113. package/dist/runtime/types/main.d.ts +2 -0
  114. package/dist/state/change/{factory.d.ts → factory/main.d.ts} +1 -1
  115. package/dist/state/change/{factory.js → factory/main.js} +8 -5
  116. package/dist/state/change/factory/ui-move.d.ts +4 -0
  117. package/dist/{runtime → state/change}/factory/ui-move.js +9 -9
  118. package/dist/state/change/helpers.d.ts +4 -2
  119. package/dist/state/change/helpers.js +11 -1
  120. package/dist/state/change/mutation.d.ts +1 -1
  121. package/dist/state/change/reducers.d.ts +3 -3
  122. package/dist/state/change/reducers.js +4 -4
  123. package/dist/state/change/types/main.d.ts +18 -0
  124. package/dist/state/change/types/main.js +1 -0
  125. package/dist/state/change/types/ui-move.d.ts +25 -0
  126. package/dist/state/change/types/ui-move.js +1 -0
  127. package/dist/state/factory.js +1 -1
  128. package/dist/state/interaction/factory.js +4 -2
  129. package/dist/state/interaction/helpers.d.ts +2 -0
  130. package/dist/state/interaction/helpers.js +3 -0
  131. package/dist/state/interaction/types/internal.d.ts +9 -1
  132. package/dist/state/types.d.ts +1 -1
  133. package/dist/wrapper/factory.js +2 -26
  134. package/package.json +17 -11
  135. package/dist/runtime/factory/ui-move.d.ts +0 -4
  136. package/dist/runtime/types/ui-move.d.ts +0 -9
  137. package/dist/state/change/types.d.ts +0 -17
  138. /package/dist/{runtime/types/ui-move.js → extensions/first-party/promotion/types/input.js} +0 -0
  139. /package/dist/{state/change/types.js → extensions/types/basic/interaction.js} +0 -0
@@ -0,0 +1,37 @@
1
+ import assert from '@ktarmyshov/assert';
2
+ import { normalizePiece } from '../../../state/board/normalize.js';
3
+ import { ALL_NON_EMPTY_PROMOTION_PIECE_CODES, DEFAULT_CONFIG } from './types/internal.js';
4
+ function assertPieceUrlsComplete(pieceUrls) {
5
+ for (const pieceCode of ALL_NON_EMPTY_PROMOTION_PIECE_CODES) {
6
+ assert(pieceCode in pieceUrls, `Missing URL for piece code: ${pieceCode}`);
7
+ }
8
+ }
9
+ function assertPieceCodeIsPromotionPieceCode(pieceCode) {
10
+ assert(pieceCode === 5 /* PieceCode.WhiteQueen */ ||
11
+ pieceCode === 4 /* PieceCode.WhiteRook */ ||
12
+ pieceCode === 3 /* PieceCode.WhiteBishop */ ||
13
+ pieceCode === 2 /* PieceCode.WhiteKnight */ ||
14
+ pieceCode === 13 /* PieceCode.BlackQueen */ ||
15
+ pieceCode === 12 /* PieceCode.BlackRook */ ||
16
+ pieceCode === 11 /* PieceCode.BlackBishop */ ||
17
+ pieceCode === 10 /* PieceCode.BlackKnight */, `Invalid promotion piece code: ${pieceCode}`);
18
+ }
19
+ function normalizePromotionPieceUrls(input) {
20
+ const normalized = {};
21
+ for (const [key, url] of Object.entries(input)) {
22
+ const pieceCode = normalizePiece(key);
23
+ assertPieceCodeIsPromotionPieceCode(pieceCode);
24
+ normalized[pieceCode] = url;
25
+ }
26
+ assertPieceUrlsComplete(normalized);
27
+ return normalized;
28
+ }
29
+ export function normalizePromotionConfig(config) {
30
+ return {
31
+ squareColor: config.squareColor ?? DEFAULT_CONFIG.squareColor,
32
+ hoverColor: config.hoverColor ?? DEFAULT_CONFIG.hoverColor,
33
+ pieceUrls: config.pieceUrls
34
+ ? normalizePromotionPieceUrls(config.pieceUrls)
35
+ : DEFAULT_CONFIG.pieceUrls
36
+ };
37
+ }
@@ -0,0 +1,10 @@
1
+ import { ColorShort, RolePromotionShort } from '../../../../state/board/types/input.js';
2
+ import { OpaqueColor } from '../../common/types.js';
3
+ import { PieceUrlsInput } from '../../main-renderer/types/input.js';
4
+ export type PromotionPieceString = `${ColorShort}${RolePromotionShort}`;
5
+ export type PromotionPieceUrlsInput = Pick<PieceUrlsInput, PromotionPieceString>;
6
+ export interface PromotionInitConfig {
7
+ squareColor?: OpaqueColor;
8
+ hoverColor?: OpaqueColor;
9
+ pieceUrls?: PromotionPieceUrlsInput;
10
+ }
@@ -0,0 +1,12 @@
1
+ import { NonEmptyPieceCode, PieceCode } from '../../../../state/board/types/internal.js';
2
+ import { OpaqueColor } from '../../common/types.js';
3
+ export type PromotionPieceCode = Exclude<NonEmptyPieceCode, PieceCode.WhitePawn | PieceCode.BlackPawn | PieceCode.BlackKing | PieceCode.WhiteKing>;
4
+ export type PromotionPieceUrls = Record<PromotionPieceCode, string>;
5
+ export interface PromotionConfig {
6
+ squareColor: OpaqueColor;
7
+ hoverColor: OpaqueColor;
8
+ pieceUrls: PromotionPieceUrls;
9
+ }
10
+ export declare const PROMOTION_CHESSNUT_PIECE_URLS: PromotionPieceUrls;
11
+ export declare const ALL_NON_EMPTY_PROMOTION_PIECE_CODES: PromotionPieceCode[];
12
+ export declare const DEFAULT_CONFIG: PromotionConfig;
@@ -0,0 +1,22 @@
1
+ export const PROMOTION_CHESSNUT_PIECE_URLS = {
2
+ [5 /* PieceCode.WhiteQueen */]: new URL('../../../../../assets/pieces/chessnut/wQ.svg', import.meta.url).toString(),
3
+ [4 /* PieceCode.WhiteRook */]: new URL('../../../../../assets/pieces/chessnut/wR.svg', import.meta.url).toString(),
4
+ [3 /* PieceCode.WhiteBishop */]: new URL('../../../../../assets/pieces/chessnut/wB.svg', import.meta.url).toString(),
5
+ [2 /* PieceCode.WhiteKnight */]: new URL('../../../../../assets/pieces/chessnut/wN.svg', import.meta.url).toString(),
6
+ [13 /* PieceCode.BlackQueen */]: new URL('../../../../../assets/pieces/chessnut/bQ.svg', import.meta.url).toString(),
7
+ [12 /* PieceCode.BlackRook */]: new URL('../../../../../assets/pieces/chessnut/bR.svg', import.meta.url).toString(),
8
+ [11 /* PieceCode.BlackBishop */]: new URL('../../../../../assets/pieces/chessnut/bB.svg', import.meta.url).toString(),
9
+ [10 /* PieceCode.BlackKnight */]: new URL('../../../../../assets/pieces/chessnut/bN.svg', import.meta.url).toString()
10
+ };
11
+ export const ALL_NON_EMPTY_PROMOTION_PIECE_CODES = Object.keys(PROMOTION_CHESSNUT_PIECE_URLS).map((code) => Number(code));
12
+ export const DEFAULT_CONFIG = {
13
+ squareColor: {
14
+ color: 'rgba(255, 255, 255)',
15
+ opacity: 1
16
+ },
17
+ hoverColor: {
18
+ color: '#000000',
19
+ opacity: 0.15
20
+ },
21
+ pieceUrls: PROMOTION_CHESSNUT_PIECE_URLS
22
+ };
@@ -0,0 +1,24 @@
1
+ import { RolePromotionCode, Square } from '../../../../state/board/types/internal.js';
2
+ import { ExtensionDefinition, ExtensionInstance } from '../../../types/extension.js';
3
+ import { ExtensionRuntimeSurface } from '../../../types/surface/main.js';
4
+ import { ExtensionInternalBase } from '../../common/types.js';
5
+ import { PromotionConfig } from './internal.js';
6
+ export declare const EXTENSION_SLOTS: readonly ["animation"];
7
+ export type ExtensionSlotsType = typeof EXTENSION_SLOTS;
8
+ export declare const EXTENSION_ID: "promotion";
9
+ export type PromotionDefinition = ExtensionDefinition<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
10
+ export type PromotionInstance = ExtensionInstance<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
11
+ export interface PromotionPieceNode {
12
+ readonly svg: SVGImageElement;
13
+ readonly rect: SVGRectElement;
14
+ }
15
+ export interface PromotionInstanceInternal extends ExtensionInternalBase<ExtensionSlotsType> {
16
+ readonly config: PromotionConfig;
17
+ readonly svgPromotionPieces: Map<RolePromotionCode, PromotionPieceNode>;
18
+ readonly activePromotionSquares: Map<Square, RolePromotionCode>;
19
+ svgHoverRect: SVGRectElement | null;
20
+ readonly runtimeSurface: ExtensionRuntimeSurface;
21
+ }
22
+ export declare const enum DirtyLayer {
23
+ Promotion = 1
24
+ }
@@ -0,0 +1,2 @@
1
+ export const EXTENSION_SLOTS = ['animation'];
2
+ export const EXTENSION_ID = 'promotion';
@@ -2,7 +2,7 @@ import assert from '@ktarmyshov/assert';
2
2
  import { toMerged } from 'es-toolkit';
3
3
  import { createSvgElement, updateElementAttributes } from '../../../render/svg/helpers.js';
4
4
  import { isUpdateContextRenderable } from '../../types/context/update.js';
5
- import { extensionCreateInternalBase, extensionDestroy, extensionMount, extensionUnmount } from '../common/helpers.js';
5
+ import { extensionCreateInternalBase, extensionDestroyBase, extensionMountBase, extensionUnmountBase } from '../common/helpers.js';
6
6
  import { DEFAULT_CONFIG, EXTENSION_ID, EXTENSION_SLOTS } from './types.js';
7
7
  export function createSelectedSquare(config = {}) {
8
8
  const mergedConfig = toMerged(DEFAULT_CONFIG, config);
@@ -29,7 +29,7 @@ function createSelectedSquareInstance(config) {
29
29
  return {
30
30
  id: EXTENSION_ID,
31
31
  mount(env) {
32
- extensionMount(internalState, env.slotRoots);
32
+ extensionMountBase(internalState, env.slotRoots);
33
33
  },
34
34
  onUpdate(context) {
35
35
  const needsRender = context.mutation.hasMutation({
@@ -55,12 +55,12 @@ function createSelectedSquareInstance(config) {
55
55
  return;
56
56
  }
57
57
  const geometry = context.currentFrame.layout.geometry;
58
- const r = geometry.squareRect(selectedSquare);
58
+ const r = geometry.getSquareRect(selectedSquare);
59
59
  const rectAttributes = {
60
60
  x: r.x.toString(),
61
61
  y: r.y.toString(),
62
- width: r.size.toString(),
63
- height: r.size.toString(),
62
+ width: r.width.toString(),
63
+ height: r.height.toString(),
64
64
  fill: internalState.config.color,
65
65
  'fill-opacity': internalState.config.opacity.toString(),
66
66
  'shape-rendering': 'crispEdges'
@@ -77,11 +77,11 @@ function createSelectedSquareInstance(config) {
77
77
  }
78
78
  },
79
79
  unmount() {
80
- extensionUnmount(internalState);
80
+ extensionUnmountBase(internalState);
81
81
  extensionClean(internalState);
82
82
  },
83
83
  destroy() {
84
- extensionDestroy(internalState);
84
+ extensionDestroyBase(internalState);
85
85
  extensionClean(internalState);
86
86
  }
87
87
  };
@@ -1,6 +1,6 @@
1
1
  import { PartialDeep } from 'type-fest';
2
2
  import { ExtensionDefinition, ExtensionInstance } from '../../types/extension.js';
3
- import { ExtensionInternal, OpaqueColor } from '../common/types.js';
3
+ import { ExtensionInternalBase, OpaqueColor } from '../common/types.js';
4
4
  export declare const EXTENSION_SLOTS: readonly ["underPieces"];
5
5
  export type ExtensionSlotsType = typeof EXTENSION_SLOTS;
6
6
  export declare const EXTENSION_ID: "selectedSquare";
@@ -9,7 +9,7 @@ export declare const DEFAULT_CONFIG: SelectedSquareConfig;
9
9
  export type SelectedSquareInitConfig = PartialDeep<SelectedSquareConfig>;
10
10
  export type SelectedSquareDefinition = ExtensionDefinition<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
11
11
  export type SelectedSquareInstance = ExtensionInstance<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
12
- export interface SelectedSquareInstanceInternal extends ExtensionInternal<ExtensionSlotsType> {
12
+ export interface SelectedSquareInstanceInternal extends ExtensionInternalBase<ExtensionSlotsType> {
13
13
  svgRect: SVGRectElement | null;
14
14
  readonly config: SelectedSquareConfig;
15
15
  }
@@ -1,8 +1 @@
1
- export { createActiveTarget } from './first-party/active-target/factory.js';
2
- export { createBoardEvents } from './first-party/board-events/factory.js';
3
- export { createLastMove } from './first-party/last-move/factory.js';
4
- export { createLegalMoves } from './first-party/legal-moves/factory.js';
5
- export { createMainRenderer } from './first-party/main-renderer/factory.js';
6
- export { createSelectedSquare } from './first-party/selected-square/factory.js';
7
- export type { AnyExtensionDefinition, ExtensionDefinitionId, ExtensionDefinitionPublicApi } from './types/extension.js';
8
- export type { BuiltInExtensionId, DefaultBuiltinChessboardExtensions } from './types/wrapper.js';
1
+ export { builtInExtensionFactoryMap, type BuiltInExtensionId } from './types/wrapper.js';
@@ -1,6 +1 @@
1
- export { createActiveTarget } from './first-party/active-target/factory.js';
2
- export { createBoardEvents } from './first-party/board-events/factory.js';
3
- export { createLastMove } from './first-party/last-move/factory.js';
4
- export { createLegalMoves } from './first-party/legal-moves/factory.js';
5
- export { createMainRenderer } from './first-party/main-renderer/factory.js';
6
- export { createSelectedSquare } from './first-party/selected-square/factory.js';
1
+ export { builtInExtensionFactoryMap } from './types/wrapper.js';
@@ -1,34 +1,11 @@
1
1
  import { Square } from '../../../state/board/types/internal.js';
2
2
  import { ScenePoint } from '../basic/transient-visuals.js';
3
- interface SceneEventBase {
4
- readonly defaultPrevented: boolean;
5
- preventDefault(): void;
3
+ export interface ScenePointerEvent {
4
+ readonly type: 'pointercancel' | 'pointerdown' | 'pointerenter' | 'pointerleave' | 'pointermove' | 'pointerout' | 'pointerover' | 'pointerrawupdate' | 'pointerup';
5
+ readonly point: ScenePoint;
6
+ readonly clampedPoint: ScenePoint;
7
+ readonly boardClampedPoint: ScenePoint | null;
8
+ readonly targetSquare: Square | null;
6
9
  }
7
- export interface ScenePointerEvent extends SceneEventBase {
8
- readonly type: 'pointerdown' | 'pointermove' | 'pointerup' | 'pointercancel' | 'pointerleave';
9
- readonly pointerId: number;
10
- readonly isPrimary: boolean;
11
- readonly button: number;
12
- readonly buttons: number;
13
- readonly ctrlKey: boolean;
14
- readonly altKey: boolean;
15
- readonly shiftKey: boolean;
16
- readonly metaKey: boolean;
17
- readonly rawPoint: ScenePoint | null;
18
- readonly clampedPoint: ScenePoint | null;
19
- readonly target: Square | null;
20
- }
21
- export type ScenePointerEventType = ScenePointerEvent['type'];
22
- export declare const SCENE_POINTER_EVENT_TYPES: ScenePointerEventType[];
23
- export interface SceneKeyboardEvent extends SceneEventBase {
24
- readonly type: 'keydown' | 'keyup';
25
- readonly key: string;
26
- readonly repeat: boolean;
27
- readonly ctrlKey: boolean;
28
- readonly altKey: boolean;
29
- readonly shiftKey: boolean;
30
- readonly metaKey: boolean;
31
- }
32
- export type SceneEvent = ScenePointerEvent | SceneKeyboardEvent;
33
- export type SceneEventType = SceneEvent['type'];
34
- export {};
10
+ export declare const ALL_SCENE_POINTER_EVENT_TYPES: ReadonlySet<string>;
11
+ export type SceneEvent = ScenePointerEvent;
@@ -1,7 +1,11 @@
1
- export const SCENE_POINTER_EVENT_TYPES = [
1
+ export const ALL_SCENE_POINTER_EVENT_TYPES = new Set([
2
+ 'pointercancel',
2
3
  'pointerdown',
4
+ 'pointerenter',
5
+ 'pointerleave',
3
6
  'pointermove',
4
- 'pointerup',
5
- 'pointercancel',
6
- 'pointerleave'
7
- ];
7
+ 'pointerout',
8
+ 'pointerover',
9
+ 'pointerrawupdate',
10
+ 'pointerup'
11
+ ]);
@@ -0,0 +1,21 @@
1
+ import { ReadonlyDeep } from 'type-fest';
2
+ import type { PieceCode, Square } from '../../../state/board/types/internal.js';
3
+ export interface ExtensionDragSessionBase {
4
+ sourceSquare: Square | null;
5
+ sourcePieceCode: PieceCode | null;
6
+ targetSquare: Square | null;
7
+ }
8
+ export interface ExtensionDragSessionLiftedPiece extends ExtensionDragSessionBase {
9
+ type: 'lifted-piece-drag';
10
+ sourcePieceCode: PieceCode;
11
+ }
12
+ export interface ExtensionDragSessionReleaseTargeting extends ExtensionDragSessionBase {
13
+ type: 'release-targeting';
14
+ }
15
+ type ExtensionCustomDragSessionType = `ext:${string}`;
16
+ export interface ExtensionDragSessionCustom extends ExtensionDragSessionBase {
17
+ type: ExtensionCustomDragSessionType;
18
+ }
19
+ export type ExtensionDragSession = ExtensionDragSessionLiftedPiece | ExtensionDragSessionReleaseTargeting | ExtensionDragSessionCustom;
20
+ export type ExtensionDragSessionSnapshot = ReadonlyDeep<ExtensionDragSession>;
21
+ export {};
@@ -5,6 +5,7 @@ export interface ScenePoint {
5
5
  }
6
6
  export interface TransientInput {
7
7
  target: Square | null;
8
- rawPoint: ScenePoint;
8
+ point: ScenePoint;
9
9
  clampedPoint: ScenePoint;
10
+ boardClampedPoint: ScenePoint;
10
11
  }
@@ -0,0 +1,5 @@
1
+ import { SceneEvent } from '../basic/events.js';
2
+ export interface ExtensionOnEventContext {
3
+ rawEvent: Event;
4
+ sceneEvent: SceneEvent | null;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,16 +1,4 @@
1
- import { MoveRequest, Square } from '../../../state/board/types/internal.js';
2
- import { MoveDestinationSnapshot } from '../../../state/interaction/types/internal.js';
3
- export type ExtensionUIMoveRequestStatus = 'unresolved' | 'deferred' | 'resolved';
4
- export interface ExtensionUIMoveRequestContextSnapshot {
5
- readonly status: ExtensionUIMoveRequestStatus;
6
- readonly sourceSquare: Square;
7
- readonly destination: MoveDestinationSnapshot;
8
- readonly canBeAutoResolved: boolean;
9
- readonly resolvedMoveRequest: MoveRequest | null;
10
- }
11
- export interface ExtensionUIMoveRequestContext extends ExtensionUIMoveRequestContextSnapshot {
12
- defer(): void;
13
- resolve(request: MoveRequest): void;
14
- autoresolve(): void;
15
- getSnapshot(): ExtensionUIMoveRequestContextSnapshot;
1
+ import { PendingUIMoveRequest } from '../../../state/change/types/ui-move.js';
2
+ export interface ExtensionPendingUIMoveRequestContext {
3
+ readonly request: PendingUIMoveRequest;
16
4
  }
@@ -1,25 +1,27 @@
1
- import { SceneEvent } from './basic/events.js';
1
+ import { ExtensionDragSessionSnapshot } from './basic/interaction.js';
2
2
  import { ExtensionInstanceMountOptions, ExtensionSlotName } from './basic/mount.js';
3
3
  import { ExtensionAnimationFinishedContext, ExtensionCleanAnimationContext, ExtensionPrepareAnimationContext, ExtensionRenderAnimationContext } from './context/animation.js';
4
+ import { ExtensionOnEventContext } from './context/events.js';
4
5
  import { ExtensionRenderContext } from './context/render.js';
5
6
  import { ExtensionRenderTransientVisualsContext } from './context/transient-visuals.js';
6
- import { ExtensionUIMoveRequestContext } from './context/ui-move.js';
7
+ import { ExtensionPendingUIMoveRequestContext } from './context/ui-move.js';
7
8
  import { ExtensionUpdateContext } from './context/update.js';
8
9
  import { ExtensionRuntimeSurface } from './surface/main.js';
9
10
  interface ExtensionInstanceBase<TId extends string, TSlots extends readonly ExtensionSlotName[]> {
10
11
  readonly id: TId;
11
- mount(env: ExtensionInstanceMountOptions<TSlots>): void;
12
- unmount(): void;
13
- destroy(): void;
14
- onUpdate(context: ExtensionUpdateContext): void;
15
- onUIMoveRequest?(context: ExtensionUIMoveRequestContext): void;
12
+ mount?(env: ExtensionInstanceMountOptions<TSlots>): void;
13
+ unmount?(): void;
14
+ destroy?(): void;
15
+ onUpdate?(context: ExtensionUpdateContext): void;
16
16
  render?(context: ExtensionRenderContext): void;
17
17
  prepareAnimation?(context: ExtensionPrepareAnimationContext): void;
18
18
  renderAnimation?(context: ExtensionRenderAnimationContext): void;
19
19
  onAnimationFinished?(context: ExtensionAnimationFinishedContext): void;
20
20
  cleanAnimation?(context: ExtensionCleanAnimationContext): void;
21
+ completeDrag?(session: ExtensionDragSessionSnapshot): void;
21
22
  renderTransientVisuals?(context: ExtensionRenderTransientVisualsContext): void;
22
- onEvent?(event: SceneEvent): void;
23
+ onUIMoveRequest?(context: ExtensionPendingUIMoveRequestContext): void;
24
+ onEvent?(context: ExtensionOnEventContext): void;
23
25
  }
24
26
  type ExtensionInstancePublicPart<TPublic> = [TPublic] extends [never] ? Record<never, never> : {
25
27
  getPublic(): TPublic;
@@ -1,11 +1,13 @@
1
1
  import { RuntimeReadonlyMutationSession } from '../../runtime/mutation/types.js';
2
+ import { DragSessionExtensionOwned } from '../../state/interaction/types/internal.js';
2
3
  import { ExtensionInvalidationState } from '../invalidation/types.js';
3
4
  import { ExtensionAnimationControllerInternalSurface } from './basic/animation.js';
4
- import { SceneEventType } from './basic/events.js';
5
5
  import { UpdateFrameSnapshot } from './basic/update.js';
6
- import { ExtensionUIMoveRequestContext } from './context/ui-move.js';
6
+ import { ExtensionOnEventContext } from './context/events.js';
7
+ import { ExtensionPendingUIMoveRequestContext } from './context/ui-move.js';
7
8
  import { AnyExtensionDefinition, AnyExtensionInstance } from './extension.js';
8
- import { ExtensionRuntimeSurfaceCommands } from './surface/commands.js';
9
+ import { ExtensionRuntimeSurfaceCommandsInternalSurface } from './surface/commands.js';
10
+ import { ExtensionRuntimeSurfaceEvents } from './surface/events.js';
9
11
  export interface ExtensionSystemExtensionRecord {
10
12
  readonly id: string;
11
13
  readonly definition: AnyExtensionDefinition;
@@ -14,13 +16,14 @@ export interface ExtensionSystemExtensionRecord {
14
16
  readonly animation: ExtensionAnimationControllerInternalSurface;
15
17
  }
16
18
  export interface ExtensionSystemInitOptions {
17
- extensionRuntimeSurfaceCommands: ExtensionRuntimeSurfaceCommands;
19
+ extensionRuntimeSurfaceCommands: ExtensionRuntimeSurfaceCommandsInternalSurface;
20
+ extensionRuntimeSurfaceEvents: ExtensionRuntimeSurfaceEvents;
18
21
  extensions?: readonly AnyExtensionDefinition[];
19
22
  }
20
23
  export interface ExtensionSystemInternal {
21
24
  readonly extensions: Map<string, ExtensionSystemExtensionRecord>;
22
25
  readonly transientVisualsSubscribers: Set<string>;
23
- readonly eventSubscribers: Map<string, Set<SceneEventType>>;
26
+ readonly eventSubscribers: Map<string, Set<string>>;
24
27
  currentFrame: UpdateFrameSnapshot | null;
25
28
  }
26
29
  export interface ExtensionSystemUpdateRequest {
@@ -37,7 +40,9 @@ export interface ExtensionSystem {
37
40
  getPublicRecord(): Readonly<Record<string, unknown>>;
38
41
  getSharedDataForRenderSystem(): ExtensionSystemSharedDataForRenderSystem;
39
42
  onUpdate(request: ExtensionSystemUpdateRequest): void;
40
- onUIMoveRequest(context: ExtensionUIMoveRequestContext): void;
43
+ onUIMoveRequest(context: ExtensionPendingUIMoveRequestContext): void;
44
+ onEvent(context: ExtensionOnEventContext): void;
45
+ completeDrag(session: DragSessionExtensionOwned): void;
41
46
  onUnmount(): void;
42
47
  onDestroy(): void;
43
48
  }
@@ -1,8 +1,11 @@
1
1
  import { LayoutSnapshot } from '../../../layout/types.js';
2
2
  import { ColorInput, MoveRequestInput, PiecePositionInput, PositionInput, SquareString } from '../../../state/board/types/input.js';
3
3
  import { Move } from '../../../state/board/types/internal.js';
4
+ import { DeferredUIMoveResolutionDetails } from '../../../state/change/types/ui-move.js';
4
5
  import { MovabilityInput } from '../../../state/interaction/types/input.js';
6
+ import { DragSessionExtensionOwned } from '../../../state/interaction/types/internal.js';
5
7
  import { RuntimeStateSnapshot } from '../../../state/types.js';
8
+ import { ExtensionDragSession } from '../basic/interaction.js';
6
9
  export interface ExtensionRuntimeSurfaceCommandsSnapshot {
7
10
  readonly state: RuntimeStateSnapshot;
8
11
  readonly layout: LayoutSnapshot;
@@ -19,8 +22,14 @@ export interface ExtensionRuntimeSurfaceCommands {
19
22
  setOrientation(orientation: ColorInput): boolean;
20
23
  setMovability(movability: MovabilityInput): boolean;
21
24
  select(square: SquareString | null): boolean;
25
+ startDrag(session: ExtensionDragSession): boolean;
22
26
  clearActiveInteraction(): boolean;
23
27
  clearInteraction(): boolean;
28
+ resolveDeferredUIMoveRequest(details: DeferredUIMoveResolutionDetails): Move;
29
+ cancelDeferredUIMoveRequest(): boolean;
24
30
  requestRender(request: ExtensionRuntimeSurfaceCommandsRenderRequest): void;
25
31
  getSnapshot(): ExtensionRuntimeSurfaceCommandsSnapshot;
26
32
  }
33
+ export interface ExtensionRuntimeSurfaceCommandsInternalSurface extends ExtensionRuntimeSurfaceCommands {
34
+ startDrag(session: DragSessionExtensionOwned): boolean;
35
+ }
@@ -1,5 +1,4 @@
1
- import { SceneEventType } from '../basic/events.js';
2
1
  export interface ExtensionRuntimeSurfaceEvents {
3
- subscribe(events: Iterable<SceneEventType>): void;
4
- unsubscribe(events?: Iterable<SceneEventType>): void;
2
+ subscribeEvent<K extends keyof HTMLElementEventMap>(type: K): void;
3
+ unsubscribeEvent<K extends keyof HTMLElementEventMap>(type: K): void;
5
4
  }
@@ -1,26 +1,27 @@
1
1
  /**
2
2
  * Public built-in extension ids accepted by createBoard({ extensions })
3
3
  */
4
- import { ActiveTargetDefinition } from '../first-party/active-target/types.js';
5
- import { BoardEventsDefinition } from '../first-party/board-events/types.js';
6
- import { LastMoveDefinition } from '../first-party/last-move/types.js';
7
- import { LegalMovesDefinition } from '../first-party/legal-moves/types.js';
8
- import { MainRendererDefinition } from '../first-party/main-renderer/types/extension.js';
9
- import { SelectedSquareDefinition } from '../first-party/selected-square/types.js';
10
- export declare const DefaultBuiltinChessboardExtensions: readonly ["mainRenderer", "events", "selectedSquare", "activeTarget", "legalMoves", "lastMove"];
11
- export type BuiltInExtensionId = (typeof DefaultBuiltinChessboardExtensions)[number];
12
- /**
13
- * Default built-in extensions used when createBoard(...) receives no extensions option
14
- */
4
+ import { createActiveTarget } from '../first-party/active-target/factory.js';
5
+ import { createAutoPromote } from '../first-party/auto-promote/factory.js';
6
+ import { createBoardEvents } from '../first-party/board-events/factory.js';
7
+ import { createLastMove } from '../first-party/last-move/factory.js';
8
+ import { createLegalMoves } from '../first-party/legal-moves/factory.js';
9
+ import { createMainRenderer } from '../first-party/main-renderer/factory.js';
10
+ import { createPromotion } from '../first-party/promotion/factory.js';
11
+ import { createSelectedSquare } from '../first-party/selected-square/factory.js';
12
+ export declare const builtInExtensionFactoryMap: {
13
+ renderer: typeof createMainRenderer;
14
+ selectedSquare: typeof createSelectedSquare;
15
+ lastMove: typeof createLastMove;
16
+ activeTarget: typeof createActiveTarget;
17
+ legalMoves: typeof createLegalMoves;
18
+ events: typeof createBoardEvents;
19
+ autoPromote: typeof createAutoPromote;
20
+ promotion: typeof createPromotion;
21
+ };
22
+ export type BuiltInExtensionId = keyof typeof builtInExtensionFactoryMap;
23
+ export type BuiltInExtensionDefinitionMap = {
24
+ [Id in BuiltInExtensionId]: ReturnType<(typeof builtInExtensionFactoryMap)[Id]>;
25
+ };
26
+ export declare const DefaultBuiltinChessboardExtensions: readonly ["renderer", "selectedSquare", "lastMove", "activeTarget", "legalMoves", "events", "autoPromote", "promotion"];
15
27
  export type DefaultBuiltinChessboardExtensions = typeof DefaultBuiltinChessboardExtensions;
16
- /**
17
- * Map built-in public ids -> concrete extension definition types
18
- */
19
- export interface BuiltInExtensionDefinitionMap {
20
- mainRenderer: MainRendererDefinition;
21
- events: BoardEventsDefinition;
22
- selectedSquare: SelectedSquareDefinition;
23
- activeTarget: ActiveTargetDefinition;
24
- legalMoves: LegalMovesDefinition;
25
- lastMove: LastMoveDefinition;
26
- }
@@ -1,11 +1,39 @@
1
1
  /**
2
2
  * Public built-in extension ids accepted by createBoard({ extensions })
3
3
  */
4
+ import { createActiveTarget } from '../first-party/active-target/factory.js';
5
+ import { EXTENSION_ID as EXTENSION_ID_ACTIVE_TARGET } from '../first-party/active-target/types.js';
6
+ import { createAutoPromote } from '../first-party/auto-promote/factory.js';
7
+ import { EXTENSION_ID as EXTENSION_ID_AUTO_PROMOTE } from '../first-party/auto-promote/types.js';
8
+ import { createBoardEvents } from '../first-party/board-events/factory.js';
9
+ import { EXTENSION_ID as EXTENSION_ID_BOARD_EVENTS } from '../first-party/board-events/types.js';
10
+ import { createLastMove } from '../first-party/last-move/factory.js';
11
+ import { EXTENSION_ID as EXTENSION_ID_LAST_MOVE } from '../first-party/last-move/types.js';
12
+ import { createLegalMoves } from '../first-party/legal-moves/factory.js';
13
+ import { EXTENSION_ID as EXTENSION_ID_LEGAL_MOVES } from '../first-party/legal-moves/types.js';
14
+ import { createMainRenderer } from '../first-party/main-renderer/factory.js';
15
+ import { EXTENSION_ID as EXTENSION_ID_RENDERER } from '../first-party/main-renderer/types/extension.js';
16
+ import { createPromotion } from '../first-party/promotion/factory.js';
17
+ import { EXTENSION_ID as EXTENSION_ID_PROMOTION } from '../first-party/promotion/types/main.js';
18
+ import { createSelectedSquare } from '../first-party/selected-square/factory.js';
19
+ import { EXTENSION_ID as EXTENSION_ID_SELECTED_SQUARE } from '../first-party/selected-square/types.js';
20
+ export const builtInExtensionFactoryMap = {
21
+ [EXTENSION_ID_RENDERER]: createMainRenderer,
22
+ [EXTENSION_ID_SELECTED_SQUARE]: createSelectedSquare,
23
+ [EXTENSION_ID_LAST_MOVE]: createLastMove,
24
+ [EXTENSION_ID_ACTIVE_TARGET]: createActiveTarget,
25
+ [EXTENSION_ID_LEGAL_MOVES]: createLegalMoves,
26
+ [EXTENSION_ID_BOARD_EVENTS]: createBoardEvents,
27
+ [EXTENSION_ID_AUTO_PROMOTE]: createAutoPromote,
28
+ [EXTENSION_ID_PROMOTION]: createPromotion
29
+ };
4
30
  export const DefaultBuiltinChessboardExtensions = [
5
- 'mainRenderer',
6
- 'events',
7
- 'selectedSquare',
8
- 'activeTarget',
9
- 'legalMoves',
10
- 'lastMove'
31
+ EXTENSION_ID_RENDERER,
32
+ EXTENSION_ID_SELECTED_SQUARE,
33
+ EXTENSION_ID_LAST_MOVE,
34
+ EXTENSION_ID_ACTIVE_TARGET,
35
+ EXTENSION_ID_LEGAL_MOVES,
36
+ EXTENSION_ID_BOARD_EVENTS,
37
+ EXTENSION_ID_AUTO_PROMOTE,
38
+ EXTENSION_ID_PROMOTION
11
39
  ];
@@ -1,4 +1,4 @@
1
- import { ExtensionUIMoveRequestContext } from './types/context/ui-move.js';
1
+ import { ExtensionPendingUIMoveRequestContext } from './types/context/ui-move.js';
2
2
  import { ExtensionSystemInternal, ExtensionSystemUpdateRequest } from './types/main.js';
3
3
  export declare function extensionSystemUpdateState(state: ExtensionSystemInternal, request: ExtensionSystemUpdateRequest): void;
4
- export declare function extensionSystemUpdateUIMoveRequest(state: ExtensionSystemInternal, context: ExtensionUIMoveRequestContext): void;
4
+ export declare function extensionSystemUpdateUIMoveRequest(state: ExtensionSystemInternal, context: ExtensionPendingUIMoveRequestContext): void;
@@ -16,7 +16,7 @@ export function extensionSystemUpdateState(state, request) {
16
16
  : {
17
17
  ...contextCommon
18
18
  };
19
- extension.instance.onUpdate(context);
19
+ extension.instance.onUpdate?.(context);
20
20
  }
21
21
  state.currentFrame = request.state;
22
22
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export { createBoard } from './wrapper/factory.js';
2
- export type { Chessboard, ChessboardExtensionInput, ChessboardInitOptions, ChessboardRuntimeSurface } from './wrapper/types.js';
2
+ export type { Chessboard, ChessboardExtensionInput, ChessboardInitOptions } from './wrapper/types.js';
3
3
  export type { MoveRequestInput, PiecePositionRecordString } from './state/board/types/input.js';
4
- export type { RuntimeStateInitOptions } from './state/types.js';
@@ -2,7 +2,7 @@ import { cloneDeep } from 'es-toolkit/object';
2
2
  import { layoutRefreshGeometry } from './reducers.js';
3
3
  function createLayoutInternal() {
4
4
  return {
5
- boardSize: 0,
5
+ sceneSize: null,
6
6
  orientation: 0 /* ColorCode.White */,
7
7
  geometry: null,
8
8
  layoutEpoch: 0
@@ -11,8 +11,8 @@ function createLayoutInternal() {
11
11
  export function createLayout() {
12
12
  const internalState = createLayoutInternal();
13
13
  return {
14
- get boardSize() {
15
- return internalState.boardSize;
14
+ get sceneSize() {
15
+ return internalState.sceneSize;
16
16
  },
17
17
  get orientation() {
18
18
  return internalState.orientation;
@@ -1,12 +1,3 @@
1
1
  import { ColorCode } from '../../state/board/types/internal.js';
2
- import { RenderGeometry } from './types.js';
3
- /**
4
- * Create RenderGeometry for a given board size (in px) and orientation.
5
- * - Geometry uses an SVG-local coordinate system with origin at top-left.
6
- * - Orientation mapping:
7
- * - 'white': files increase left→right (a..h), ranks increase bottom→top (1..8).
8
- * yIndex = 7 - rank, xIndex = file
9
- * - 'black': files increase right→left (a..h), ranks increase top→bottom (1..8).
10
- * yIndex = rank, xIndex = 7 - file
11
- */
12
- export declare function createRenderGeometry(boardSize: number, orientation: ColorCode): RenderGeometry;
2
+ import { SceneRenderGeometry, Size } from './types.js';
3
+ export declare function createRenderGeometry(sceneSize: Size, orientation: ColorCode): SceneRenderGeometry;