cm-chessboard 8.13.0 → 8.14.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.
package/README.md CHANGED
@@ -214,6 +214,11 @@ The event has the following **`event.type`**:
214
214
  recapture premoves. Return `true` to commit it (e.g. castling by clicking the rook). When you return `false` here the
215
215
  clicked own piece simply becomes the new selection, so if you show illegal-move feedback, skip it when `event.squareTo`
216
216
  still holds one of the mover's own pieces.
217
+ A move made by click always plays its own move animation. Set `event.animate = false` before returning to skip it for this move only
218
+ (e.g. a premove made by click); this is read once, right after validation, so there is nothing to reset afterward.
219
+ The opt-out only applies to click moves. A drag move never animates its completion, so `event.animate = true` has no effect there.
220
+ Extensions receive a clone of the event and therefore opt out by setting `chessboard.state.moveInputAnimate = false`
221
+ in their `moveInput` extension point handler instead.
217
222
  - **`INPUT_EVENT_TYPE.moveInputCanceled`**: The user canceled the move with clicking again on the start square, clicking
218
223
  outside the board or right click.
219
224
  - **`INPUT_EVENT_TYPE.moveInputFinished`**: Fired after the move was made, also when canceled.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cm-chessboard",
3
- "version": "8.13.0",
3
+ "version": "8.14.0",
4
4
  "description": "A JavaScript chessboard which is lightweight, ES6 module based, responsive, SVG rendered and without dependencies.",
5
5
  "keywords": [
6
6
  "chess",
@@ -14,6 +14,9 @@ export class ChessboardState {
14
14
  this.inputBlackEnabled = false
15
15
  this.squareSelectEnabled = false
16
16
  this.moveInputCallback = null
17
+ // set per move from `event.animate` in the validateMoveInput callback; `false` skips
18
+ // the completion animation of a click move (see ChessboardView/VisualMoveInput)
19
+ this.moveInputAnimate = undefined
17
20
  this.extensionPoints = {}
18
21
  this.moveInputProcess = Promise.resolve()
19
22
  }
@@ -421,6 +421,11 @@ export class ChessboardView {
421
421
  if (this.chessboard.state.moveInputCallback) {
422
422
  data.moveInputCallbackResult = this.chessboard.state.moveInputCallback(data)
423
423
  }
424
+ // A validator can set `event.animate = false` to skip this move's own completion animation
425
+ // (e.g. a premove made by click, which would otherwise always animate).
426
+ // Assigned before the extension points on purpose: extensions receive a clone of `data`,
427
+ // so they opt out by setting `state.moveInputAnimate` directly, which must not be clobbered here.
428
+ this.chessboard.state.moveInputAnimate = data.animate
424
429
  this.chessboard.state.invokeExtensionPoints(EXTENSION_POINT.moveInput, data)
425
430
  return data.moveInputCallbackResult
426
431
  }
@@ -178,7 +178,10 @@ export class VisualMoveInput {
178
178
  const validated = params.validated !== undefined ?
179
179
  params.validated : this.validateMoveInputCallback(this.fromSquare, this.toSquare)
180
180
  if (this.toSquare && validated) {
181
- this.chessboard.movePiece(this.fromSquare, this.toSquare, prevState === MOVE_INPUT_STATE.clickTo).then(() => {
181
+ // A click move always completes with its own animation, unless the
182
+ // validator opted out via `event.animate = false` (see ChessboardView).
183
+ const animate = prevState === MOVE_INPUT_STATE.clickTo && this.chessboard.state.moveInputAnimate !== false
184
+ this.chessboard.movePiece(this.fromSquare, this.toSquare, animate).then(() => {
182
185
  if (prevState === MOVE_INPUT_STATE.clickTo) {
183
186
  this.view.setPieceVisibility(this.toSquare, true)
184
187
  }
@@ -124,6 +124,58 @@ describe("TestVisualMoveInput", () => {
124
124
  board.destroy()
125
125
  })
126
126
 
127
+ // A click move always completes with its own animation (see the test above),
128
+ // which is unwanted for premoves made by click. `event.animate = false` in the
129
+ // validator lets a consumer opt out per-move instead of having to toggle
130
+ // `chessboard.props.style.animationDuration` around the move.
131
+ it("should skip a click move's own animation when the validator sets event.animate = false", async () => {
132
+ const board = newBoard()
133
+ let capturedAnimated = null
134
+ const originalMovePiece = board.movePiece.bind(board)
135
+ board.movePiece = (from, to, animated) => {
136
+ capturedAnimated = animated
137
+ return originalMovePiece(from, to, animated)
138
+ }
139
+ board.enableMoveInput((e) => {
140
+ if (e.type === INPUT_EVENT_TYPE.validateMoveInput) {
141
+ e.animate = false
142
+ return true
143
+ }
144
+ return true
145
+ }, COLOR.white)
146
+ const vmi = board.view.visualMoveInput
147
+
148
+ vmi.onPointerDown(mouseDown("e2"))
149
+ vmi.onPointerUp(mouseUp("e2"))
150
+ vmi.onPointerDown(mouseDown("e4"))
151
+ await tick()
152
+
153
+ assert.equal(capturedAnimated, false)
154
+ assert.equal(board.getPiece("e4"), "wp")
155
+ board.destroy()
156
+ })
157
+
158
+ it("should still animate a click move by default (event.animate untouched)", async () => {
159
+ const board = newBoard()
160
+ let capturedAnimated = null
161
+ const originalMovePiece = board.movePiece.bind(board)
162
+ board.movePiece = (from, to, animated) => {
163
+ capturedAnimated = animated
164
+ return originalMovePiece(from, to, animated)
165
+ }
166
+ board.enableMoveInput(() => true, COLOR.white)
167
+ const vmi = board.view.visualMoveInput
168
+
169
+ vmi.onPointerDown(mouseDown("e2"))
170
+ vmi.onPointerUp(mouseUp("e2"))
171
+ vmi.onPointerDown(mouseDown("e4"))
172
+ await tick()
173
+
174
+ assert.equal(capturedAnimated, true)
175
+ assert.equal(board.getPiece("e4"), "wp");
176
+ board.destroy()
177
+ })
178
+
127
179
  it("should complete a drag move to a new square", async () => {
128
180
  const board = newBoard()
129
181
  board.enableMoveInput(() => true, COLOR.white)