feat(ui): add ParamPiecePicker component

This commit is contained in:
Joey Yakimowich-Payne 2026-04-26 12:34:46 -06:00
commit 90942bc4a6
No known key found for this signature in database
2 changed files with 74 additions and 0 deletions

View file

@ -0,0 +1,39 @@
import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { describe, it, expect, vi } from 'vitest';
import { ParamPiecePicker } from './ParamPiecePicker';
describe('ParamPiecePicker', () => {
const pieces = [
{ id: 1, type: 'queen', color: 'white' as const, square: 28 }, // e4
{ id: 2, type: 'knight', color: 'black' as const, square: 62 }, // g8
];
it('renders dropdown listing pieces with color, type and square name', () => {
const html = renderToStaticMarkup(
<ParamPiecePicker
value={1}
onChange={() => {}}
pieces={pieces}
/>
);
expect(html).toContain('white queen at e4');
expect(html).toContain('black knight at g8');
expect(html).toContain('value="1"');
expect(html).toContain('value="2"');
});
it('calls onChange with entityId when selecting an option', () => {
// Testing React component events without testing-library:
// We instantiate the component directly and call its props.onChange to verify the type
const onChange = vi.fn();
const component = ParamPiecePicker({ value: 1, onChange, pieces });
// Trigger the onChange handler passed to the select element
component.props.onChange({ target: { value: '2' } } as unknown as React.ChangeEvent<HTMLSelectElement>);
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith(2);
});
});

View file

@ -0,0 +1,35 @@
import React from 'react';
import { squareToAlgebraic } from '../coord';
export interface ParamPiecePickerProps {
value: number | undefined;
onChange: (entityId: number) => void;
pieces: readonly {
id: number;
type: string;
color: "white" | "black";
square: number;
}[];
}
export function ParamPiecePicker({ value, onChange, pieces }: ParamPiecePickerProps) {
return (
<select
value={value ?? ''}
onChange={(e) => {
const val = e.target.value;
if (val) {
onChange(Number(val));
}
}}
className="p-1 text-sm bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded"
>
<option value="" disabled>Select a piece</option>
{pieces.map((p) => (
<option key={p.id} value={p.id}>
{p.color} {p.type} at {squareToAlgebraic(p.square)}
</option>
))}
</select>
);
}