@mirasen/chessboard 1.2.4 → 1.3.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +72 -1
  3. package/dist/animation/planner.js +2 -1
  4. package/dist/extensions/build/index.d.ts +1 -1
  5. package/dist/extensions/first-party/annotations/update.js +1 -1
  6. package/dist/extensions/first-party/board-events/factory.js +2 -2
  7. package/dist/extensions/first-party/main-renderer/animation/factory.d.ts +2 -1
  8. package/dist/extensions/first-party/main-renderer/animation/factory.js +3 -2
  9. package/dist/extensions/first-party/main-renderer/animation/types.d.ts +2 -0
  10. package/dist/extensions/first-party/main-renderer/animation/update.js +4 -2
  11. package/dist/extensions/first-party/main-renderer/board/factory.d.ts +1 -1
  12. package/dist/extensions/first-party/main-renderer/board/factory.js +4 -4
  13. package/dist/extensions/first-party/main-renderer/board/render.js +1 -1
  14. package/dist/extensions/first-party/main-renderer/board/types.d.ts +1 -1
  15. package/dist/extensions/first-party/main-renderer/coordinates/factory.d.ts +1 -1
  16. package/dist/extensions/first-party/main-renderer/coordinates/factory.js +2 -2
  17. package/dist/extensions/first-party/main-renderer/coordinates/render.js +1 -1
  18. package/dist/extensions/first-party/main-renderer/coordinates/types.d.ts +1 -1
  19. package/dist/extensions/first-party/main-renderer/denormalize.d.ts +3 -0
  20. package/dist/extensions/first-party/main-renderer/denormalize.js +18 -0
  21. package/dist/extensions/first-party/main-renderer/drag/factory.d.ts +2 -1
  22. package/dist/extensions/first-party/main-renderer/drag/factory.js +2 -1
  23. package/dist/extensions/first-party/main-renderer/drag/render.js +18 -11
  24. package/dist/extensions/first-party/main-renderer/drag/types.d.ts +2 -0
  25. package/dist/extensions/first-party/main-renderer/drag/update.js +4 -2
  26. package/dist/extensions/first-party/main-renderer/factory.d.ts +2 -1
  27. package/dist/extensions/first-party/main-renderer/factory.js +46 -12
  28. package/dist/extensions/first-party/main-renderer/normalize.d.ts +3 -3
  29. package/dist/extensions/first-party/main-renderer/normalize.js +19 -7
  30. package/dist/extensions/first-party/main-renderer/pieces/suppress.js +2 -1
  31. package/dist/extensions/first-party/main-renderer/public-defaults.d.ts +3 -0
  32. package/dist/extensions/first-party/main-renderer/public-defaults.js +4 -0
  33. package/dist/extensions/first-party/main-renderer/types/extension.d.ts +8 -5
  34. package/dist/extensions/first-party/main-renderer/types/instance.d.ts +10 -8
  35. package/dist/extensions/first-party/main-renderer/types/internal.d.ts +6 -7
  36. package/dist/extensions/first-party/main-renderer/types/internal.js +24 -1
  37. package/dist/extensions/first-party/main-renderer/types/public.d.ts +9 -0
  38. package/dist/extensions/first-party/main-renderer/types/template.d.ts +12 -1
  39. package/dist/extensions/first-party/promotion/types/input.d.ts +2 -2
  40. package/dist/extensions/index.d.ts +1 -0
  41. package/dist/extensions/index.js +1 -0
  42. package/dist/extensions/types/basic/events.d.ts +30 -16
  43. package/dist/extensions/types/basic/interaction.d.ts +12 -2
  44. package/dist/extensions/types/surface/commands.d.ts +4 -2
  45. package/dist/index.d.ts +10 -0
  46. package/dist/index.js +11 -0
  47. package/dist/runtime/factory/input.js +50 -24
  48. package/dist/runtime/factory/main.js +11 -0
  49. package/dist/runtime/input/adapter/types.js +2 -1
  50. package/dist/runtime/input/controller/factory.js +36 -9
  51. package/dist/runtime/input/controller/helpers.d.ts +5 -0
  52. package/dist/runtime/input/controller/helpers.js +11 -0
  53. package/dist/runtime/input/controller/pointer.js +48 -21
  54. package/dist/runtime/input/controller/types.d.ts +13 -4
  55. package/dist/runtime/mutation/interaction.js +1 -1
  56. package/dist/runtime/mutation/types.d.ts +2 -2
  57. package/dist/state/interaction/config.d.ts +6 -0
  58. package/dist/state/interaction/config.js +30 -0
  59. package/dist/state/interaction/factory.js +15 -3
  60. package/dist/state/interaction/helpers.d.ts +18 -2
  61. package/dist/state/interaction/helpers.js +12 -0
  62. package/dist/state/interaction/mutation.d.ts +2 -0
  63. package/dist/state/interaction/reducers.d.ts +3 -0
  64. package/dist/state/interaction/reducers.js +22 -7
  65. package/dist/state/interaction/types/config.d.ts +9 -0
  66. package/dist/state/interaction/types/config.js +1 -0
  67. package/dist/state/interaction/types/input.d.ts +3 -0
  68. package/dist/state/interaction/types/internal.d.ts +14 -4
  69. package/dist/state/interaction/types/main.d.ts +11 -5
  70. package/dist/wrapper/factory.js +2 -0
  71. package/dist/wrapper/types.d.ts +1 -1
  72. package/package.json +5 -6
  73. package/dist/extensions/first-party/main-renderer/types/input.d.ts +0 -4
  74. /package/dist/extensions/first-party/main-renderer/types/{input.js → public.js} +0 -0
@@ -1,6 +1,7 @@
1
+ import { isDragSessionActiveLiftedPiece } from '../../../../state/interaction/helpers.js';
1
2
  export function calculateSuppressedSquares(_state, context, animationSuppressedSquares) {
2
3
  const dragSession = context.currentFrame.state.interaction.dragSession;
3
- const dragSquare = dragSession?.type === 'lifted-piece-drag' ? dragSession.sourceSquare : null;
4
+ const dragSquare = dragSession && isDragSessionActiveLiftedPiece(dragSession) ? dragSession.sourceSquare : null;
4
5
  const result = new Set(animationSuppressedSquares);
5
6
  if (dragSquare !== null) {
6
7
  result.add(dragSquare);
@@ -0,0 +1,3 @@
1
+ import type { MainRendererConfigPublic } from './types/public.js';
2
+ export declare const DefaultMainRendererDesktopConfigPublic: MainRendererConfigPublic;
3
+ export declare const DefaultMainRendererMobileConfigPublic: MainRendererConfigPublic;
@@ -0,0 +1,4 @@
1
+ import { denormalizeMainRendererConfig } from './denormalize.js';
2
+ import { DefaultMainRendererDesktopConfig, DefaultMainRendererMobileConfig } from './types/internal.js';
3
+ export const DefaultMainRendererDesktopConfigPublic = denormalizeMainRendererConfig(DefaultMainRendererDesktopConfig);
4
+ export const DefaultMainRendererMobileConfigPublic = denormalizeMainRendererConfig(DefaultMainRendererMobileConfig);
@@ -1,11 +1,14 @@
1
- import { ExtensionDefinition, ExtensionInstance } from '../../../types/extension.js';
2
- import { MainRendererConfigInput } from './input.js';
3
- export type MainRendererInitOptions = Partial<MainRendererConfigInput>;
1
+ import type { ExtensionDefinition, ExtensionInstance } from '../../../types/extension.js';
2
+ import type { MainRendererConfigPublic, MainRendererSetConfigOptions } from './public.js';
4
3
  export declare const EXTENSION_SLOTS: readonly ["defs", "board", "coordinates", "pieces", "animation", "drag"];
5
4
  export type ExtensionSlotsType = typeof EXTENSION_SLOTS;
6
5
  export declare const EXTENSION_ID: "renderer";
7
- export type MainRendererDefinition = ExtensionDefinition<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
8
- export type MainRendererInstance = ExtensionInstance<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, never>;
6
+ export interface RendererPublicAPI {
7
+ setConfig(options: MainRendererSetConfigOptions): void;
8
+ getConfig(): MainRendererConfigPublic;
9
+ }
10
+ export type MainRendererDefinition = ExtensionDefinition<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, RendererPublicAPI>;
11
+ export type MainRendererInstance = ExtensionInstance<typeof EXTENSION_ID, typeof EXTENSION_SLOTS, RendererPublicAPI>;
9
12
  export declare enum DirtyLayer {
10
13
  Board = 1,// 1 << 0,
11
14
  Coordinates = 2,// 1 << 1,
@@ -1,12 +1,13 @@
1
- import { ExtensionRuntimeSurface } from '../../../types/surface/main.js';
2
- import { ExtensionInternalBase } from '../../common/types.js';
3
- import { MainRendererAnimation } from '../animation/types.js';
4
- import { MainRendererBoard } from '../board/types.js';
5
- import { MainRendererCoordinates } from '../coordinates/types.js';
6
- import { MainRendererDrag } from '../drag/types.js';
1
+ import type { ExtensionRuntimeSurface } from '../../../types/surface/main.js';
2
+ import type { ExtensionInternalBase } from '../../common/types.js';
3
+ import type { MainRendererAnimation } from '../animation/types.js';
4
+ import type { MainRendererBoard } from '../board/types.js';
5
+ import type { MainRendererCoordinates } from '../coordinates/types.js';
6
+ import type { MainRendererDrag } from '../drag/types.js';
7
7
  import type { PieceSymbolResolver } from '../piece-symbols.js';
8
- import { MainRendererPieces } from '../pieces/types.js';
9
- import { ExtensionSlotsType } from './extension.js';
8
+ import type { MainRendererPieces } from '../pieces/types.js';
9
+ import type { ExtensionSlotsType } from './extension.js';
10
+ import type { MainRendererConfig } from './internal.js';
10
11
  export interface MainRendererInstanceInternal extends ExtensionInternalBase<ExtensionSlotsType> {
11
12
  readonly board: MainRendererBoard;
12
13
  readonly coordinates: MainRendererCoordinates;
@@ -15,4 +16,5 @@ export interface MainRendererInstanceInternal extends ExtensionInternalBase<Exte
15
16
  readonly animation: MainRendererAnimation;
16
17
  readonly runtimeSurface: ExtensionRuntimeSurface;
17
18
  readonly pieceSymbolResolver: PieceSymbolResolver;
19
+ config: MainRendererConfig;
18
20
  }
@@ -1,5 +1,6 @@
1
- import { NonEmptyPieceCode } from '../../../../state/board/types/internal.js';
2
- import { TMainRendererConfig } from './template.js';
1
+ import type { ReadonlyDeep } from 'type-fest';
2
+ import type { NonEmptyPieceCode } from '../../../../state/board/types/internal.js';
3
+ import type { TMainRendererConfig } from './template.js';
3
4
  export interface ConfigColorPair {
4
5
  light: string;
5
6
  dark: string;
@@ -9,9 +10,7 @@ export interface ConfigColors {
9
10
  coordinates: ConfigColorPair;
10
11
  }
11
12
  export type PieceUrls = Record<NonEmptyPieceCode, string>;
12
- export type MainRendererConfig = TMainRendererConfig<PieceUrls>;
13
+ export type MainRendererConfig = ReadonlyDeep<TMainRendererConfig<PieceUrls>>;
13
14
  export declare const CHESSNUT_PIECE_URLS: PieceUrls;
14
- /**
15
- * Default board renderer configuration.
16
- */
17
- export declare const DEFAULT_MAIN_RENDERER_CONFIG: MainRendererConfig;
15
+ export declare const DefaultMainRendererDesktopConfig: MainRendererConfig;
16
+ export declare const DefaultMainRendererMobileConfig: MainRendererConfig;
@@ -1,3 +1,4 @@
1
+ import { cloneDeep } from 'es-toolkit';
1
2
  export const CHESSNUT_PIECE_URLS = {
2
3
  [6 /* PieceCode.WhiteKing */]: new URL('../../../../../assets/pieces/chessnut/wK.svg', import.meta.url).toString(),
3
4
  [5 /* PieceCode.WhiteQueen */]: new URL('../../../../../assets/pieces/chessnut/wQ.svg', import.meta.url).toString(),
@@ -15,7 +16,7 @@ export const CHESSNUT_PIECE_URLS = {
15
16
  /**
16
17
  * Default board renderer configuration.
17
18
  */
18
- export const DEFAULT_MAIN_RENDERER_CONFIG = {
19
+ const DefaultMainRendererConfigPart = {
19
20
  colors: {
20
21
  board: {
21
22
  light: '#d7dde5',
@@ -28,3 +29,25 @@ export const DEFAULT_MAIN_RENDERER_CONFIG = {
28
29
  },
29
30
  pieceUrls: CHESSNUT_PIECE_URLS
30
31
  };
32
+ export const DefaultMainRendererDesktopConfig = {
33
+ ...cloneDeep(DefaultMainRendererConfigPart),
34
+ drag: {
35
+ pieceScale: 1,
36
+ pieceAnchor: 'center',
37
+ pieceAnchorOffsetY: 0
38
+ },
39
+ animation: {
40
+ durationMs: 180
41
+ }
42
+ };
43
+ export const DefaultMainRendererMobileConfig = {
44
+ ...cloneDeep(DefaultMainRendererConfigPart),
45
+ drag: {
46
+ pieceScale: 2,
47
+ pieceAnchor: 'bottom',
48
+ pieceAnchorOffsetY: 0.14
49
+ },
50
+ animation: {
51
+ durationMs: 180
52
+ }
53
+ };
@@ -0,0 +1,9 @@
1
+ import type { PartialDeep, ReadonlyDeep, WritableDeep } from 'type-fest';
2
+ import type { PieceString } from '../../../../state/board/types/input.js';
3
+ import type { TMainRendererConfig } from './template.js';
4
+ export type PieceUrlsPublic = Record<PieceString, string>;
5
+ export type MainRendererConfigPublic = ReadonlyDeep<TMainRendererConfig<PieceUrlsPublic>>;
6
+ export interface MainRendererInitOptions extends PartialDeep<WritableDeep<MainRendererConfigPublic>> {
7
+ pieceUrls?: PieceUrlsPublic;
8
+ }
9
+ export type MainRendererSetConfigOptions = Omit<MainRendererInitOptions, 'pieceUrls'>;
@@ -1,5 +1,16 @@
1
- import { ConfigColors } from './internal.js';
1
+ import type { ConfigColors } from './internal.js';
2
+ export type MainRendererConfigDragPieceAnchor = 'center' | 'bottom';
3
+ export interface MainRendererConfigDrag {
4
+ pieceScale: number;
5
+ pieceAnchor: MainRendererConfigDragPieceAnchor;
6
+ pieceAnchorOffsetY: number;
7
+ }
8
+ export interface MainRendererConfigAnimation {
9
+ durationMs: number;
10
+ }
2
11
  export interface TMainRendererConfig<TPieceUrls> {
3
12
  colors: ConfigColors;
4
13
  pieceUrls: TPieceUrls;
14
+ drag: MainRendererConfigDrag;
15
+ animation: MainRendererConfigAnimation;
5
16
  }
@@ -1,8 +1,8 @@
1
1
  import { ColorShort, RolePromotionShort } from '../../../../state/board/types/input.js';
2
2
  import { OpaqueColor } from '../../common/types.js';
3
- import { PieceUrlsInput } from '../../main-renderer/types/input.js';
3
+ import { PieceUrlsPublic } from '../../main-renderer/types/public.js';
4
4
  export type PromotionPieceString = `${ColorShort}${RolePromotionShort}`;
5
- export type PromotionPieceUrlsInput = Pick<PieceUrlsInput, PromotionPieceString>;
5
+ export type PromotionPieceUrlsInput = Pick<PieceUrlsPublic, PromotionPieceString>;
6
6
  export interface PromotionInitConfig {
7
7
  squareColor?: OpaqueColor;
8
8
  hoverColor?: OpaqueColor;
@@ -1 +1,2 @@
1
+ export { DefaultMainRendererDesktopConfigPublic as DefaultMainRendererDesktopConfig, DefaultMainRendererMobileConfigPublic as DefaultMainRendererMobileConfig } from './first-party/main-renderer/public-defaults.js';
1
2
  export { builtInExtensionFactoryMap, type BuiltInExtensionId } from './types/wrapper.js';
@@ -1 +1,2 @@
1
+ export { DefaultMainRendererDesktopConfigPublic as DefaultMainRendererDesktopConfig, DefaultMainRendererMobileConfigPublic as DefaultMainRendererMobileConfig } from './first-party/main-renderer/public-defaults.js';
1
2
  export { builtInExtensionFactoryMap } from './types/wrapper.js';
@@ -11,29 +11,43 @@ export interface ScenePointerEvent {
11
11
  readonly targetSquare: Square | null;
12
12
  }
13
13
  export type SceneEvent = ScenePointerEvent;
14
- export type RuntimeInteractionActionStartLiftedDrag = {
15
- type: 'startLiftedDrag';
16
- source: Square;
17
- target: Square;
14
+ export type RuntimeInteractionActionStartPendingLiftedDragSession = {
15
+ type: 'startLiftedDragSession';
16
+ phase: 'pending';
17
+ sourceSquare: Square;
18
+ targetSquare: Square;
18
19
  startButton: number;
20
+ startPoint: ScenePoint;
21
+ thresholdPx: number;
19
22
  };
20
- export type RuntimeInteractionActionStartReleaseTargetingDrag = {
21
- type: 'startReleaseTargetingDrag';
22
- source: Square;
23
- target: Square;
23
+ export type RuntimeInteractionActionStartActiveLiftedDragSession = {
24
+ type: 'startLiftedDragSession';
25
+ phase: 'active';
26
+ sourceSquare: Square;
27
+ targetSquare: Square;
24
28
  startButton: number;
25
29
  };
26
- export type RuntimeInteractionActionCompleteCoreDrag = {
27
- type: 'completeCoreDragTo';
28
- target: Square;
30
+ export type RuntimeInteractionActionActivatePendingLiftedDragSession = {
31
+ type: 'activatePendingLiftedDragSession';
32
+ targetSquare: Square | null;
29
33
  };
30
- export type RuntimeInteractionActionCompleteExtensionDrag = {
31
- type: 'completeExtensionDrag';
32
- target: Square | null;
34
+ export type RuntimeInteractionActionStartReleaseTargetingDragSession = {
35
+ type: 'startReleaseTargetingDragSession';
36
+ sourceSquare: Square;
37
+ targetSquare: Square;
38
+ startButton: number;
39
+ };
40
+ export type RuntimeInteractionActionCompleteCoreDragSessionTo = {
41
+ type: 'completeCoreDragSessionTo';
42
+ targetSquare: Square;
43
+ };
44
+ export type RuntimeInteractionActionCompleteExtensionDragSession = {
45
+ type: 'completeExtensionDragSession';
46
+ targetSquare: Square | null;
33
47
  };
34
48
  export type RuntimeInteractionActionUpdateDragSessionCurrentTarget = {
35
49
  type: 'updateDragSessionCurrentTarget';
36
- target: Square | null;
50
+ targetSquare: Square | null;
37
51
  };
38
52
  export type RuntimeInteractionActionCancelActiveInteraction = {
39
53
  type: 'cancelActiveInteraction';
@@ -41,5 +55,5 @@ export type RuntimeInteractionActionCancelActiveInteraction = {
41
55
  export type RuntimeInteractionActionCancelInteraction = {
42
56
  type: 'cancelInteraction';
43
57
  };
44
- export type RuntimeInteractionAction = RuntimeInteractionActionStartLiftedDrag | RuntimeInteractionActionStartReleaseTargetingDrag | RuntimeInteractionActionCompleteCoreDrag | RuntimeInteractionActionCompleteExtensionDrag | RuntimeInteractionActionUpdateDragSessionCurrentTarget | RuntimeInteractionActionCancelActiveInteraction | RuntimeInteractionActionCancelInteraction;
58
+ export type RuntimeInteractionAction = RuntimeInteractionActionStartPendingLiftedDragSession | RuntimeInteractionActionStartActiveLiftedDragSession | RuntimeInteractionActionActivatePendingLiftedDragSession | RuntimeInteractionActionStartReleaseTargetingDragSession | RuntimeInteractionActionCompleteCoreDragSessionTo | RuntimeInteractionActionCompleteExtensionDragSession | RuntimeInteractionActionUpdateDragSessionCurrentTarget | RuntimeInteractionActionCancelActiveInteraction | RuntimeInteractionActionCancelInteraction;
45
59
  export {};
@@ -1,15 +1,25 @@
1
- import { ReadonlyDeep } from 'type-fest';
1
+ import type { ReadonlyDeep } from 'type-fest';
2
2
  import type { PieceCode, Square } from '../../../state/board/types/internal.js';
3
+ import type { ScenePoint } from './transient-visuals.js';
3
4
  export interface ExtensionDragSessionBase {
4
5
  sourceSquare: Square | null;
5
6
  sourcePieceCode: PieceCode | null;
6
7
  targetSquare: Square | null;
7
8
  startButton: number;
8
9
  }
9
- export interface ExtensionDragSessionLiftedPiece extends ExtensionDragSessionBase {
10
+ export interface ExtensionDragSessionLiftedPieceBase extends ExtensionDragSessionBase {
10
11
  type: 'lifted-piece-drag';
11
12
  sourcePieceCode: PieceCode;
12
13
  }
14
+ export interface ExtensionDragSessionPendingLiftedPiece extends ExtensionDragSessionLiftedPieceBase {
15
+ phase: 'pending';
16
+ startPoint: ScenePoint;
17
+ thresholdPx: number;
18
+ }
19
+ export interface ExtensionDragSessionActiveLiftedPiece extends ExtensionDragSessionLiftedPieceBase {
20
+ phase: 'active';
21
+ }
22
+ export type ExtensionDragSessionLiftedPiece = ExtensionDragSessionPendingLiftedPiece | ExtensionDragSessionActiveLiftedPiece;
13
23
  export interface ExtensionDragSessionReleaseTargeting extends ExtensionDragSessionBase {
14
24
  type: 'release-targeting';
15
25
  }
@@ -2,8 +2,8 @@ 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
4
  import { DeferredUIMoveResolutionDetails } from '../../../state/change/types/ui-move.js';
5
- import { MovabilityInput } from '../../../state/interaction/types/input.js';
6
- import { DragSessionExtensionOwned } from '../../../state/interaction/types/internal.js';
5
+ import { InteractionConfigInput, MovabilityInput } from '../../../state/interaction/types/input.js';
6
+ import { DragSessionExtensionOwned, InteractionConfigSnapshot } from '../../../state/interaction/types/internal.js';
7
7
  import { RuntimeStateSnapshot } from '../../../state/types.js';
8
8
  import { ExtensionDragSession } from '../basic/interaction.js';
9
9
  export interface ExtensionRuntimeSurfaceCommandsSnapshot {
@@ -25,6 +25,8 @@ export interface ExtensionRuntimeSurfaceCommands {
25
25
  startDrag(session: ExtensionDragSession): boolean;
26
26
  clearActiveInteraction(): boolean;
27
27
  clearInteraction(): boolean;
28
+ setInteractionConfig(config: InteractionConfigInput): boolean;
29
+ getInteractionConfig(): InteractionConfigSnapshot;
28
30
  resolveDeferredUIMoveRequest(details: DeferredUIMoveResolutionDetails): Move;
29
31
  cancelDeferredUIMoveRequest(): boolean;
30
32
  requestRender(request: ExtensionRuntimeSurfaceCommandsRenderRequest): boolean;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,15 @@
1
+ import type { MainRendererConfigPublic } from './extensions/first-party/main-renderer/types/public.js';
2
+ import { DefaultInteractionDesktopConfig, DefaultInteractionMobileConfig } from './state/interaction/config.js';
3
+ import type { InteractionConfig } from './state/interaction/types/config.js';
1
4
  export type { ColorInput, MoveRequestInput, PiecePositionRecordString, PositionInput } from './state/board/types/input.js';
2
5
  export type { MoveOutput } from './state/board/types/output.js';
3
6
  export type { MovabilityInput, MoveDestinationInput } from './state/interaction/types/input.js';
4
7
  export { createBoard } from './wrapper/factory.js';
5
8
  export type { Chessboard, ChessboardExtensionInput, ChessboardInitOptions } from './wrapper/types.js';
9
+ export interface ChessboardConfig {
10
+ readonly interaction: InteractionConfig;
11
+ readonly renderer: MainRendererConfigPublic;
12
+ }
13
+ export { DefaultInteractionDesktopConfig, DefaultInteractionMobileConfig };
14
+ export declare const DefaultChessboardDesktopConfig: ChessboardConfig;
15
+ export declare const DefaultChessboardMobileConfig: ChessboardConfig;
package/dist/index.js CHANGED
@@ -1 +1,12 @@
1
+ import { DefaultMainRendererDesktopConfig, DefaultMainRendererMobileConfig } from './extensions/index.js';
2
+ import { DefaultInteractionDesktopConfig, DefaultInteractionMobileConfig } from './state/interaction/config.js';
1
3
  export { createBoard } from './wrapper/factory.js';
4
+ export { DefaultInteractionDesktopConfig, DefaultInteractionMobileConfig };
5
+ export const DefaultChessboardDesktopConfig = {
6
+ interaction: DefaultInteractionDesktopConfig,
7
+ renderer: DefaultMainRendererDesktopConfig
8
+ };
9
+ export const DefaultChessboardMobileConfig = {
10
+ interaction: DefaultInteractionMobileConfig,
11
+ renderer: DefaultMainRendererMobileConfig
12
+ };
@@ -1,6 +1,7 @@
1
1
  import assert from '@ktarmyshov/assert';
2
2
  import { isEmptyPieceCode } from '../../state/board/check.js';
3
- import { isDragSessionCoreOwned } from '../../state/interaction/helpers.js';
3
+ import { isDragSessionActiveLiftedPiece, isDragSessionCoreOwned, isDragSessionReleaseTargeting } from '../../state/interaction/helpers.js';
4
+ import { isStartPendingLiftedDragSessionInput } from '../input/controller/helpers.js';
4
5
  import { runtimeRunMutationPipeline } from '../mutation/run.js';
5
6
  import { uiMoveCompleteTo } from './helpers.js';
6
7
  export function notifyExtensionCancelDragIfOwned(internalState, dragSession) {
@@ -18,68 +19,93 @@ export function createRuntimeInteractionSurface(state) {
18
19
  const internalState = state();
19
20
  return internalState.state.board.getPieceCodeAt(square);
20
21
  },
21
- startLiftedDrag(source, target, startButton) {
22
+ startLiftedDragSession(input) {
22
23
  const internalState = state();
23
24
  const interactionMutationSession = internalState.mutation.getSession();
24
25
  const interaction = internalState.state.interaction;
25
- const pieceCode = internalState.state.board.getPieceCodeAt(source);
26
+ const pieceCode = internalState.state.board.getPieceCodeAt(input.sourceSquare);
26
27
  assert(!isEmptyPieceCode(pieceCode), 'Cannot start a lifted-piece-drag session from an empty square');
27
28
  const interactionSource = {
28
- square: source,
29
+ square: input.sourceSquare,
29
30
  pieceCode
30
31
  };
31
32
  interaction.setSelected(interactionSource, interactionMutationSession);
32
- const dragSession = {
33
- owner: 'core',
34
- type: 'lifted-piece-drag',
35
- sourceSquare: interactionSource.square,
36
- sourcePieceCode: interactionSource.pieceCode,
37
- targetSquare: target,
38
- startButton
39
- };
33
+ const dragSession = isStartPendingLiftedDragSessionInput(input)
34
+ ? {
35
+ owner: 'core',
36
+ type: 'lifted-piece-drag',
37
+ phase: 'pending',
38
+ sourceSquare: interactionSource.square,
39
+ sourcePieceCode: interactionSource.pieceCode,
40
+ targetSquare: input.targetSquare,
41
+ startButton: input.startButton,
42
+ startPoint: input.startPoint,
43
+ thresholdPx: input.thresholdPx
44
+ }
45
+ : {
46
+ owner: 'core',
47
+ type: 'lifted-piece-drag',
48
+ phase: 'active',
49
+ sourceSquare: interactionSource.square,
50
+ sourcePieceCode: interactionSource.pieceCode,
51
+ targetSquare: input.targetSquare,
52
+ startButton: input.startButton
53
+ };
40
54
  interaction.setDragSession(dragSession, interactionMutationSession);
41
55
  runtimeRunMutationPipeline(internalState);
42
56
  },
57
+ activatePendingLiftedDragSession(input) {
58
+ const internalState = state();
59
+ const mutationSession = internalState.mutation.getSession();
60
+ const interaction = internalState.state.interaction;
61
+ interaction.activatePendingLiftedDragSession(input.targetSquare, mutationSession);
62
+ runtimeRunMutationPipeline(internalState);
63
+ },
43
64
  transientInput(input) {
44
65
  const internalState = state();
45
66
  internalState.renderSystem.requestRenderVisuals(input);
46
67
  },
47
- completeCoreDragTo(target) {
68
+ completeCoreDragSessionTo(target) {
48
69
  const internalState = state();
49
70
  const mutationSession = internalState.mutation.getSession();
50
71
  const interaction = internalState.state.interaction;
72
+ const currentDragSession = interaction.dragSession;
73
+ assert(currentDragSession !== null &&
74
+ isDragSessionCoreOwned(currentDragSession) &&
75
+ (isDragSessionActiveLiftedPiece(currentDragSession) ||
76
+ isDragSessionReleaseTargeting(currentDragSession)), 'completeCoreDragSessionTo requires a core-owned active lifted-piece or release-targeting drag session');
51
77
  interaction.updateDragSessionCurrentTarget(target, mutationSession);
52
78
  const dragSession = interaction.dragSession;
53
- assert(isDragSessionCoreOwned(dragSession), 'completeDragTo can only be called for core-owned drag sessions');
54
79
  uiMoveCompleteTo(internalState, target);
55
- mutationSession.addMutation('runtime.interaction.completeCoreDragTo', true, dragSession);
80
+ mutationSession.addMutation('runtime.interaction.completeCoreDragSessionTo', true, dragSession);
56
81
  runtimeRunMutationPipeline(internalState);
57
82
  },
58
- completeExtensionDrag(target) {
83
+ completeExtensionDragSession(target) {
59
84
  const internalState = state();
60
85
  const mutationSession = internalState.mutation.getSession();
61
86
  const interaction = internalState.state.interaction;
87
+ const currentDragSession = interaction.dragSession;
88
+ assert(currentDragSession !== null && !isDragSessionCoreOwned(currentDragSession), 'completeExtensionDragSession can only be called for extension-owned drag sessions');
62
89
  interaction.updateDragSessionCurrentTarget(target, mutationSession);
63
90
  const dragSession = interaction.dragSession;
64
- assert(!isDragSessionCoreOwned(dragSession), 'completeExtensionDrag can only be called for extension-owned drag sessions');
65
91
  internalState.extensionSystem.completeDrag(dragSession);
66
92
  internalState.state.interaction.setDragSession(null, mutationSession);
67
- mutationSession.addMutation('runtime.interaction.completeExtensionDragTo', true, dragSession);
93
+ mutationSession.addMutation('runtime.interaction.completeExtensionDragSession', true, dragSession);
68
94
  runtimeRunMutationPipeline(internalState);
69
95
  },
70
- startReleaseTargetingDrag(source, target, startButton) {
96
+ startReleaseTargetingDragSession(input) {
71
97
  const internalState = state();
72
98
  const mutationSession = internalState.mutation.getSession();
73
99
  const interaction = internalState.state.interaction;
74
- assert(interaction.selected !== null, 'startReleaseTargetingDrag requires a selected piece');
75
- assert(interaction.selected.square === source, 'startReleaseTargetingDrag source must match selected square');
100
+ assert(interaction.selected !== null, 'startReleaseTargetingDragSession requires a selected piece');
101
+ assert(interaction.selected.square === input.sourceSquare, 'startReleaseTargetingDragSession source must match selected square');
76
102
  const dragSession = {
77
103
  owner: 'core',
78
104
  type: 'release-targeting',
79
- sourceSquare: source,
105
+ sourceSquare: input.sourceSquare,
80
106
  sourcePieceCode: interaction.selected.pieceCode,
81
- targetSquare: target,
82
- startButton
107
+ targetSquare: input.targetSquare,
108
+ startButton: input.startButton
83
109
  };
84
110
  interaction.setDragSession(dragSession, mutationSession);
85
111
  runtimeRunMutationPipeline(internalState);
@@ -91,6 +91,17 @@ function createExtensionRuntimeSurfaceCommandsInternalSurface(getInternalState)
91
91
  runtimeRunMutationPipeline(state);
92
92
  return changed;
93
93
  },
94
+ setInteractionConfig(config) {
95
+ const state = getInternalState();
96
+ const mutationSession = state.mutation.getSession();
97
+ const changed = state.state.interaction.setConfig(config, mutationSession);
98
+ runtimeRunMutationPipeline(state);
99
+ return changed;
100
+ },
101
+ getInteractionConfig() {
102
+ const state = getInternalState();
103
+ return state.state.interaction.getConfig();
104
+ },
94
105
  select(square) {
95
106
  const state = getInternalState();
96
107
  const mutationSession = state.mutation.getSession();
@@ -3,5 +3,6 @@ export const NEED_EVENT_TYPES = new Set([
3
3
  'pointermove',
4
4
  'pointerup',
5
5
  'pointercancel',
6
- 'lostpointercapture'
6
+ 'lostpointercapture',
7
+ 'dragstart'
7
8
  ]);
@@ -19,22 +19,49 @@ export function createInteractionController(options) {
19
19
  transmitTransientInput(internalState, context);
20
20
  return; // The event has been handled by the surface (extensions)
21
21
  }
22
+ else if (context.rawEvent.type === 'dragstart') {
23
+ // Prevent native drag-and-drop behavior to avoid conflicts with custom drag handling
24
+ context.rawEvent.preventDefault();
25
+ }
22
26
  if (action) {
23
27
  switch (action.type) {
24
- case 'startLiftedDrag':
25
- internalState.surface.startLiftedDrag(action.source, action.target, action.startButton);
28
+ case 'startLiftedDragSession':
29
+ internalState.surface.startLiftedDragSession(action.phase === 'pending'
30
+ ? {
31
+ phase: 'pending',
32
+ sourceSquare: action.sourceSquare,
33
+ targetSquare: action.targetSquare,
34
+ startButton: action.startButton,
35
+ startPoint: action.startPoint,
36
+ thresholdPx: action.thresholdPx
37
+ }
38
+ : {
39
+ phase: 'active',
40
+ sourceSquare: action.sourceSquare,
41
+ targetSquare: action.targetSquare,
42
+ startButton: action.startButton
43
+ });
44
+ break;
45
+ case 'activatePendingLiftedDragSession':
46
+ internalState.surface.activatePendingLiftedDragSession({
47
+ targetSquare: action.targetSquare
48
+ });
26
49
  break;
27
- case 'startReleaseTargetingDrag':
28
- internalState.surface.startReleaseTargetingDrag(action.source, action.target, action.startButton);
50
+ case 'startReleaseTargetingDragSession':
51
+ internalState.surface.startReleaseTargetingDragSession({
52
+ sourceSquare: action.sourceSquare,
53
+ targetSquare: action.targetSquare,
54
+ startButton: action.startButton
55
+ });
29
56
  break;
30
- case 'completeCoreDragTo':
31
- internalState.surface.completeCoreDragTo(action.target);
57
+ case 'completeCoreDragSessionTo':
58
+ internalState.surface.completeCoreDragSessionTo(action.targetSquare);
32
59
  break;
33
- case 'completeExtensionDrag':
34
- internalState.surface.completeExtensionDrag(action.target);
60
+ case 'completeExtensionDragSession':
61
+ internalState.surface.completeExtensionDragSession(action.targetSquare);
35
62
  break;
36
63
  case 'updateDragSessionCurrentTarget':
37
- internalState.surface.updateDragSessionCurrentTarget(action.target);
64
+ internalState.surface.updateDragSessionCurrentTarget(action.targetSquare);
38
65
  break;
39
66
  case 'cancelActiveInteraction':
40
67
  internalState.surface.cancelActiveInteraction();
@@ -1,4 +1,9 @@
1
+ import type { ScenePoint } from '../../../extensions/types/basic/transient-visuals.js';
1
2
  import type { Square } from '../../../state/board/types/internal.js';
2
3
  import type { InteractionStateSnapshot } from '../../../state/interaction/types/main.js';
4
+ import type { StartActiveLiftedDragSessionInput, StartLiftedDragSessionInput, StartPendingLiftedDragSessionInput } from './types.js';
3
5
  export declare function buttonToButtonsMask(button: number): number | null;
4
6
  export declare function canMoveTo(snapshot: InteractionStateSnapshot, target: Square): boolean;
7
+ export declare function isStartPendingLiftedDragSessionInput(input: StartLiftedDragSessionInput): input is StartPendingLiftedDragSessionInput;
8
+ export declare function isStartActiveLiftedDragSessionInput(input: StartLiftedDragSessionInput): input is StartActiveLiftedDragSessionInput;
9
+ export declare function isMovementBeyondThreshold(start: ScenePoint, current: ScenePoint, thresholdPx: number): boolean;
@@ -26,3 +26,14 @@ export function canMoveTo(snapshot, target) {
26
26
  // strict: target must be in the computed active destinations
27
27
  return snapshot.activeDestinations.has(target);
28
28
  }
29
+ export function isStartPendingLiftedDragSessionInput(input) {
30
+ return input.phase === 'pending';
31
+ }
32
+ export function isStartActiveLiftedDragSessionInput(input) {
33
+ return input.phase === 'active';
34
+ }
35
+ export function isMovementBeyondThreshold(start, current, thresholdPx) {
36
+ const dx = current.x - start.x;
37
+ const dy = current.y - start.y;
38
+ return dx * dx + dy * dy >= thresholdPx * thresholdPx;
39
+ }