@mirasen/chessboard 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +20 -1
- package/dist/extensions/first-party/legal-moves/factory.js +1 -1
- package/dist/extensions/types/basic/events.d.ts +5 -2
- package/dist/extensions/types/basic/events.js +5 -3
- package/dist/runtime/factory/main.js +0 -5
- package/dist/runtime/input/adapter/pointer.d.ts +1 -0
- package/dist/runtime/input/adapter/pointer.js +9 -0
- package/dist/runtime/input/adapter/types.js +2 -1
- package/dist/runtime/input/controller/interaction.js +3 -1
- package/dist/runtime/input/controller/pointer.d.ts +1 -0
- package/dist/runtime/input/controller/pointer.js +12 -0
- package/package.json +8 -3
- package/dist/runtime/mutation/invalidation.d.ts +0 -1
- package/dist/runtime/mutation/invalidation.js +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @mirasen/chessboard
|
|
2
2
|
|
|
3
|
+
## 1.2.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d8df60e: Fix stale lifted-piece drag cleanup when pointer capture is lost.
|
|
8
|
+
|
|
9
|
+
Fast drag gestures released outside the board could leave an active lifted-piece drag session alive if the browser delivered `lostpointercapture` instead of a normal `pointerup`. The input adapter now handles `lostpointercapture`, clears stale pointer tracking, and routes the event through the interaction controller so active drag sessions are cancelled cleanly.
|
|
10
|
+
|
|
11
|
+
This prevents dragged pieces from remaining visually attached to the pointer after an outside-board release.
|
|
12
|
+
|
|
3
13
|
## 1.2.2
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -319,16 +319,35 @@ board = createBoard({
|
|
|
319
319
|
|
|
320
320
|
Configured built-in extensions can be provided either as declarative `{ builtin, options }` objects or through the built-in extension factory map. If you use custom piece assets, pass the same `pieceUrls` map to renderer and promotion when you want the board and promotion UI to use the same piece set.
|
|
321
321
|
|
|
322
|
-
### Default visual identity
|
|
322
|
+
### Default visual identity and attribution
|
|
323
323
|
|
|
324
324
|
The default first-party extension baseline includes a subtle Mirasen board watermark.
|
|
325
325
|
|
|
326
326
|
If you want full control over the visual baseline, use an explicit extension list and omit the `watermark` extension.
|
|
327
327
|
|
|
328
|
+
Attribution is not required by the MIT license, but it is appreciated. If Mirasen Chessboard helps your project, please consider keeping the default watermark or linking to `@mirasen/chessboard`.
|
|
329
|
+
|
|
328
330
|
## Documentation
|
|
329
331
|
|
|
330
332
|
See [Documentation](./documentation.md) for the documentation hub.
|
|
331
333
|
|
|
334
|
+
## Versioning and breaking changes
|
|
335
|
+
|
|
336
|
+
`@mirasen/chessboard` follows semantic versioning for public API changes.
|
|
337
|
+
|
|
338
|
+
Breaking public API changes are released as major versions.
|
|
339
|
+
|
|
340
|
+
We do not add backward-compatibility aliases or runtime compatibility bridges by default. When a public contract changes, the new API is kept explicit and clean, and the required migration is documented in the release notes / changelog.
|
|
341
|
+
|
|
342
|
+
Migration notes for breaking changes are included directly in the corresponding changelog entry, so users can see:
|
|
343
|
+
|
|
344
|
+
- what changed
|
|
345
|
+
- why it changed
|
|
346
|
+
- what old usage looked like
|
|
347
|
+
- what new usage should look like
|
|
348
|
+
|
|
349
|
+
See the [CHANGELOG](./CHANGELOG.md) for release history and migration notes.
|
|
350
|
+
|
|
332
351
|
## Architecture
|
|
333
352
|
|
|
334
353
|
`@mirasen/chessboard` is built around explicit boundaries:
|
|
@@ -68,7 +68,7 @@ function createLegalMovesInstance(options, config) {
|
|
|
68
68
|
'stroke-opacity': internalState.config.captureTarget.color.opacity.toString(),
|
|
69
69
|
'stroke-width': (geometry.squareSize * internalState.config.captureTarget.strokeWidthRatio).toString(),
|
|
70
70
|
fill: 'none'
|
|
71
|
-
};
|
|
71
|
+
};
|
|
72
72
|
for (const [square, destination] of interaction.activeDestinations) {
|
|
73
73
|
const rect = geometry.getSquareRect(square);
|
|
74
74
|
const circleX = rect.x + geometry.squareSize / 2;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { Square } from '../../../state/board/types/internal.js';
|
|
2
2
|
import type { ScenePoint } from '../basic/transient-visuals.js';
|
|
3
|
+
declare const ALL_SCENE_POINTER_EVENT_TYPES_ARRAY: readonly ["pointercancel", "pointerdown", "pointerenter", "pointerleave", "pointermove", "pointerout", "pointerover", "pointerrawupdate", "pointerup", "contextmenu", "lostpointercapture"];
|
|
4
|
+
export type ScenePointerEventType = (typeof ALL_SCENE_POINTER_EVENT_TYPES_ARRAY)[number];
|
|
5
|
+
export declare const ALL_SCENE_POINTER_EVENT_TYPES: ReadonlySet<string>;
|
|
3
6
|
export interface ScenePointerEvent {
|
|
4
|
-
readonly type:
|
|
7
|
+
readonly type: ScenePointerEventType;
|
|
5
8
|
readonly point: ScenePoint;
|
|
6
9
|
readonly clampedPoint: ScenePoint;
|
|
7
10
|
readonly boardClampedPoint: ScenePoint | null;
|
|
8
11
|
readonly targetSquare: Square | null;
|
|
9
12
|
}
|
|
10
|
-
export declare const ALL_SCENE_POINTER_EVENT_TYPES: ReadonlySet<string>;
|
|
11
13
|
export type SceneEvent = ScenePointerEvent;
|
|
12
14
|
export type RuntimeInteractionActionStartLiftedDrag = {
|
|
13
15
|
type: 'startLiftedDrag';
|
|
@@ -38,3 +40,4 @@ export type RuntimeInteractionActionCancelInteraction = {
|
|
|
38
40
|
type: 'cancelInteraction';
|
|
39
41
|
};
|
|
40
42
|
export type RuntimeInteractionAction = RuntimeInteractionActionStartLiftedDrag | RuntimeInteractionActionStartReleaseTargetingDrag | RuntimeInteractionActionCompleteCoreDrag | RuntimeInteractionActionCompleteExtensionDrag | RuntimeInteractionActionUpdateDragSessionCurrentTarget | RuntimeInteractionActionCancelActiveInteraction | RuntimeInteractionActionCancelInteraction;
|
|
43
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const ALL_SCENE_POINTER_EVENT_TYPES_ARRAY = [
|
|
2
2
|
'pointercancel',
|
|
3
3
|
'pointerdown',
|
|
4
4
|
'pointerenter',
|
|
@@ -8,5 +8,7 @@ export const ALL_SCENE_POINTER_EVENT_TYPES = new Set([
|
|
|
8
8
|
'pointerover',
|
|
9
9
|
'pointerrawupdate',
|
|
10
10
|
'pointerup',
|
|
11
|
-
'contextmenu'
|
|
12
|
-
|
|
11
|
+
'contextmenu',
|
|
12
|
+
'lostpointercapture'
|
|
13
|
+
];
|
|
14
|
+
export const ALL_SCENE_POINTER_EVENT_TYPES = new Set(ALL_SCENE_POINTER_EVENT_TYPES_ARRAY);
|
|
@@ -195,11 +195,6 @@ export function createRuntime(options) {
|
|
|
195
195
|
internalState = createRuntimeInternal(optionsInternal);
|
|
196
196
|
// Initial creation, so we mark board position as mutated to trigger mutation pipeline
|
|
197
197
|
internalState.mutation.addMutation('state.board.setPosition', true);
|
|
198
|
-
// We will have two different interfaces here
|
|
199
|
-
// One is returned, one is for controller - with different methods
|
|
200
|
-
// At the moment our assumption that controller will use Runtime but not opposite direction
|
|
201
|
-
// So we can construct these two objects separately so they would not be huge!
|
|
202
|
-
// TODO: const inputControllerSurface = createRuntimeInputControllerSurface(internalState);
|
|
203
198
|
// Initial run to process initial mutations and set up previousContext for the next runs
|
|
204
199
|
internalStatus = 'unmounted';
|
|
205
200
|
internalState.mutation.run(internalState);
|
|
@@ -6,4 +6,5 @@ export declare function releaseCapture(state: InputAdapterInternal): void;
|
|
|
6
6
|
export declare function adapterOnPointerDown(state: InputAdapterInternal, e: PointerEvent): void;
|
|
7
7
|
export declare function adapterOnPointerUp(state: InputAdapterInternal, e: PointerEvent): void;
|
|
8
8
|
export declare function adapterOnPointerCancel(state: InputAdapterInternal, e: PointerEvent): void;
|
|
9
|
+
export declare function adapterOnLostPointerCapture(state: InputAdapterInternal, e: PointerEvent): void;
|
|
9
10
|
export declare function pointerEventDestroy(state: InputAdapterInternal): void;
|
|
@@ -24,6 +24,9 @@ function pointerEventAdapterHandler(state, e) {
|
|
|
24
24
|
case 'pointercancel':
|
|
25
25
|
adapterOnPointerCancel(state, e);
|
|
26
26
|
break;
|
|
27
|
+
case 'lostpointercapture':
|
|
28
|
+
adapterOnLostPointerCapture(state, e);
|
|
29
|
+
break;
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
32
|
/** Release capture for the currently tracked pointer and clear tracking state. */
|
|
@@ -56,6 +59,12 @@ export function adapterOnPointerCancel(state, e) {
|
|
|
56
59
|
return;
|
|
57
60
|
releaseCapture(state);
|
|
58
61
|
}
|
|
62
|
+
export function adapterOnLostPointerCapture(state, e) {
|
|
63
|
+
assert(e.type === 'lostpointercapture', `Expected lostpointercapture event, got ${e.type}`);
|
|
64
|
+
if (e.pointerId !== state.activePointerId)
|
|
65
|
+
return;
|
|
66
|
+
releaseCapture(state);
|
|
67
|
+
}
|
|
59
68
|
export function pointerEventDestroy(state) {
|
|
60
69
|
if (state.activePointerId !== null) {
|
|
61
70
|
releaseCapture(state);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { determineActionPointerCancel, determineActionPointerDown, determineActionPointerMove, determineActionPointerUp } from './pointer.js';
|
|
1
|
+
import { determineActionLostPointerCapture, determineActionPointerCancel, determineActionPointerDown, determineActionPointerMove, determineActionPointerUp } from './pointer.js';
|
|
2
2
|
export function determineRuntimeInteractionAction(state, context) {
|
|
3
3
|
switch (context.rawEvent.type) {
|
|
4
4
|
case 'pointerdown':
|
|
@@ -9,6 +9,8 @@ export function determineRuntimeInteractionAction(state, context) {
|
|
|
9
9
|
return determineActionPointerUp(state, context);
|
|
10
10
|
case 'pointercancel':
|
|
11
11
|
return determineActionPointerCancel(state, context);
|
|
12
|
+
case 'lostpointercapture':
|
|
13
|
+
return determineActionLostPointerCapture(state, context);
|
|
12
14
|
}
|
|
13
15
|
return null;
|
|
14
16
|
}
|
|
@@ -4,3 +4,4 @@ export declare function determineActionPointerDown(state: InteractionControllerI
|
|
|
4
4
|
export declare function determineActionPointerMove(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
5
5
|
export declare function determineActionPointerUp(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
6
6
|
export declare function determineActionPointerCancel(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
7
|
+
export declare function determineActionLostPointerCapture(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
@@ -129,3 +129,15 @@ export function determineActionPointerCancel(state, context) {
|
|
|
129
129
|
type: 'cancelActiveInteraction'
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
+
export function determineActionLostPointerCapture(state, context) {
|
|
133
|
+
assert(context.rawEvent.type === 'lostpointercapture', 'determineActionLostPointerCapture should only be called for lostpointercapture events');
|
|
134
|
+
const interaction = state.surface.getInteractionStateSnapshot();
|
|
135
|
+
if (!interaction.dragSession) {
|
|
136
|
+
// No active drag session, so nothing to do on lost pointer capture
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
// Cancel the active interaction on lost pointer capture
|
|
140
|
+
return {
|
|
141
|
+
type: 'cancelActiveInteraction'
|
|
142
|
+
};
|
|
143
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirasen/chessboard",
|
|
3
3
|
"description": "Framework-agnostic TypeScript chessboard platform with real chess interaction built in.",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.3",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Mirasen",
|
|
@@ -16,8 +16,13 @@
|
|
|
16
16
|
"typescript",
|
|
17
17
|
"framework-agnostic",
|
|
18
18
|
"svg",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
19
|
+
"drag-and-drop",
|
|
20
|
+
"click-to-move",
|
|
21
|
+
"animation",
|
|
22
|
+
"annotations",
|
|
23
|
+
"chessjs",
|
|
24
|
+
"legal-moves",
|
|
25
|
+
"touch"
|
|
21
26
|
],
|
|
22
27
|
"homepage": "https://mirasen.io/chessboard",
|
|
23
28
|
"repository": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|