pvpokemon/src/ts/app/components/MovesDropdown.tsx
2019-03-09 20:24:01 -05:00

173 lines
5.0 KiB
TypeScript

import React from 'react';
import { ContentRect, default as Measure } from 'react-measure';
import { FixedSizeList } from 'react-window';
import classNames from 'classnames';
import { CombatMoveStats, IPokemonMove } from 'app/models/Pokemon';
import { TypeIndicator } from './TypeIndicator';
import * as styles from 'app/styles/MovesDropdown.scss';
export interface IMovesDropdownProps {
menuLabel : string;
movesById : CombatMoveStats;
selectedMove : IPokemonMove | null;
options : Array<IPokemonMove>;
handleToggleOpen : (open : boolean) => void;
handleChangeSelectedOption : (option : IPokemonMove) => void;
}
interface IState {
isMenuOpen : boolean;
listRef : React.RefObject<FixedSizeList>;
dimensions : {
width : number;
height : number;
};
}
interface IRowFactory {
index : number;
style : React.CSSProperties;
}
export class MovesDropdown extends React.Component<IMovesDropdownProps, IState> {
constructor(props : IMovesDropdownProps) {
super(props);
this.state = {
isMenuOpen: false,
listRef: React.createRef(),
dimensions: {
width: -1,
height: -1,
}
};
}
public render() {
const {
menuLabel,
movesById,
selectedMove,
options,
} = this.props;
const {
isMenuOpen,
} = this.state;
const { width, height } = this.state.dimensions;
const onResize = (contentRect : ContentRect) => {
if (typeof contentRect.bounds !== 'undefined') {
this.setState({ dimensions: contentRect.bounds });
}
};
const wrapperCss = classNames(
'nes-select',
'dropdown',
styles.wrapper,
);
const menuCss = classNames(
'nes-container',
styles.menu,
);
let moveName = 'Select a move';
if (selectedMove !== null) {
const moveStats = movesById.get(selectedMove.id);
if (moveStats) {
moveName = moveStats.name;
} else {
moveName = 'UNKNOWN MOVE';
}
}
return (
<React.Fragment>
<div
className={ wrapperCss }
onClick={ this.toggleMenu }
>
{ moveName }
</div>
{ isMenuOpen &&
<div className={ menuCss }>
<h3 className="title">{ menuLabel }</h3>
<Measure
bounds={ true }
onResize={ onResize }
>
{
({ measureRef }) => (
<div ref={ measureRef }>
<FixedSizeList
ref={ this.state.listRef }
height={ height }
itemCount={ options.length }
itemSize={ 35 }
width={ width }
>
{ this.rowFactory.bind(this) }
</FixedSizeList>
</div>
)
}
</Measure>
</div>
}
</React.Fragment>
);
}
private readonly toggleMenu = () => {
const isMenuOpen = !this.state.isMenuOpen;
this.setState({
isMenuOpen,
});
this.props.handleToggleOpen(isMenuOpen);
}
private rowFactory({ index, style } : IRowFactory) {
const {
movesById,
selectedMove,
options,
} = this.props;
const move = options[index];
const moveStats = movesById.get(move.id);
const css = classNames(
'list-item', // global style
styles.listItem,
{
active: selectedMove && selectedMove.id === move.id,
}
);
const typeCss = classNames({
[styles.legacy]: move.isLegacy
});
const onClick = () => {
this.props.handleChangeSelectedOption(move);
this.toggleMenu();
};
return (
<React.Fragment>
{ moveStats &&
<a
key={ index }
style={ style }
className={ css }
onClick={ onClick }
>
<span>{ moveStats.name }</span>
<TypeIndicator className={ typeCss } type={ moveStats.type } />
</a>
}
</React.Fragment>
);
}
}