fix(chess): render piece overlays inside the drag-transform layer
HP pips and any other per-piece overlays lived in the grid cell as siblings of <Piece> \u2014 outside the transforming motion.div, so they stayed pinned to the origin square while the piece visually slid toward the cursor. Moved them inside the transform layer so they inherit the same x/y/rotate/scale motion values and follow the piece during drag and FLIP animations. Piece accepts overlays + pieceFacts as props; Board just forwards what it already computes. Same render cost, same wiring, visible result: pips dangle with the piece.
This commit is contained in:
parent
1e292d6c00
commit
6883539426
2 changed files with 30 additions and 12 deletions
|
|
@ -322,19 +322,11 @@ export function Board({ facts, legalMoves, onMove, turn, myColor, lastMove, chec
|
|||
piece.color === turn &&
|
||||
(myColor === null || myColor === undefined || piece.color === myColor)
|
||||
}
|
||||
overlays={overlays}
|
||||
pieceFacts={factsById.get(piece.id) ?? []}
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
/>
|
||||
{/* Per-piece preset overlays (HP pips, etc.). Each is a
|
||||
pure function of the piece's facts; Board stays
|
||||
agnostic to which presets exist. */}
|
||||
{overlays.map((Overlay, i) => (
|
||||
<Overlay
|
||||
key={i}
|
||||
pieceId={piece.id}
|
||||
pieceFacts={factsById.get(piece.id) ?? []}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { PieceColor, PieceType } from '../schema';
|
||||
import type { ChessAttrMap, ChessFact, PieceColor, PieceType } from '../schema';
|
||||
import { pieceAssets } from '../assets/pieces';
|
||||
import {
|
||||
motion,
|
||||
|
|
@ -6,8 +6,9 @@ import {
|
|||
useSpring,
|
||||
useTransform,
|
||||
} from 'motion/react';
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useLayoutEffect, useRef, useState, type ReactNode } from 'react';
|
||||
import type { DragEvent as ReactDragEvent } from 'react';
|
||||
import type { PieceOverlayComponent } from './preset-overlays';
|
||||
|
||||
export interface PieceProps {
|
||||
color: PieceColor;
|
||||
|
|
@ -18,6 +19,14 @@ export interface PieceProps {
|
|||
* ongoing, etc). When false, drag is disabled and the piece shows a
|
||||
* default cursor. */
|
||||
isDraggable: boolean;
|
||||
/** Per-piece preset overlays (HP pips, ammo counter, etc.). Rendered
|
||||
* INSIDE the drag-transform layer so they follow the piece as it's
|
||||
* translated / rotated / scaled during a drag. Pass [] when no
|
||||
* overlays are active. */
|
||||
overlays?: ReadonlyArray<PieceOverlayComponent>;
|
||||
/** Facts for this piece, used by the overlays. Pre-indexed by the
|
||||
* Board so the overlay component doesn't re-scan all facts. */
|
||||
pieceFacts?: ReadonlyArray<ChessFact<keyof ChessAttrMap>>;
|
||||
onDragStart: (pieceId: number, square: number) => void;
|
||||
onDragEnd: () => void;
|
||||
}
|
||||
|
|
@ -81,6 +90,8 @@ export function Piece({
|
|||
pieceId,
|
||||
square,
|
||||
isDraggable,
|
||||
overlays,
|
||||
pieceFacts,
|
||||
onDragStart,
|
||||
onDragEnd,
|
||||
}: PieceProps) {
|
||||
|
|
@ -344,6 +355,21 @@ export function Piece({
|
|||
}`}
|
||||
draggable={false}
|
||||
/>
|
||||
|
||||
{/*
|
||||
* Per-piece preset overlays (HP pips, etc.) live INSIDE the
|
||||
* transform layer so they inherit the drag `x/y/rotate/scale`
|
||||
* motion values and track the piece during drags. Overlays
|
||||
* that don't apply to this piece's facts return null so the
|
||||
* DOM stays clean.
|
||||
*/}
|
||||
{overlays?.map((Overlay, i) => (
|
||||
<Overlay
|
||||
key={i}
|
||||
pieceId={pieceId}
|
||||
pieceFacts={pieceFacts ?? []}
|
||||
/>
|
||||
)) as ReactNode}
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue