159 lines
3.4 KiB
JavaScript
159 lines
3.4 KiB
JavaScript
import PropTypes from 'prop-types';
|
|
import React, { Component } from 'react';
|
|
import dimensions from 'Styles/Variables/dimensions';
|
|
import Measure from 'Components/Measure';
|
|
import PageJumpBarItem from './PageJumpBarItem';
|
|
import styles from './PageJumpBar.css';
|
|
|
|
const ITEM_HEIGHT = parseInt(dimensions.jumpBarItemHeight);
|
|
|
|
class PageJumpBar extends Component {
|
|
|
|
//
|
|
// Lifecycle
|
|
|
|
constructor(props, context) {
|
|
super(props, context);
|
|
|
|
this.state = {
|
|
height: 0,
|
|
visibleItems: props.items.order
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.computeVisibleItems();
|
|
}
|
|
|
|
shouldComponentUpdate(nextProps, nextState) {
|
|
return (
|
|
nextProps.items !== this.props.items ||
|
|
nextState.height !== this.state.height ||
|
|
nextState.visibleItems !== this.state.visibleItems
|
|
);
|
|
}
|
|
|
|
componentDidUpdate(prevProps, prevState) {
|
|
if (
|
|
prevProps.items !== this.props.items ||
|
|
prevState.height !== this.state.height
|
|
) {
|
|
this.computeVisibleItems();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Control
|
|
|
|
computeVisibleItems() {
|
|
const {
|
|
items,
|
|
minimumItems
|
|
} = this.props;
|
|
|
|
if (!items) {
|
|
return;
|
|
}
|
|
|
|
const {
|
|
characters,
|
|
order
|
|
} = items;
|
|
|
|
const height = this.state.height;
|
|
const maximumItems = Math.floor(height / ITEM_HEIGHT);
|
|
const diff = order.length - maximumItems;
|
|
|
|
if (diff < 0) {
|
|
this.setState({ visibleItems: order });
|
|
return;
|
|
}
|
|
|
|
if (order.length < minimumItems) {
|
|
this.setState({ visibleItems: order });
|
|
return;
|
|
}
|
|
|
|
// get first, last, and most common in between to make up numbers
|
|
const visibleItems = [order[0]];
|
|
|
|
const sorted = order.slice(1, -1).map((x) => characters[x]).sort((a, b) => b - a);
|
|
const minCount = sorted[maximumItems - 3];
|
|
const greater = sorted.reduce((acc, value) => acc + (value > minCount ? 1 : 0), 0);
|
|
let minAllowed = maximumItems - 2 - greater;
|
|
|
|
for (let i = 1; i < order.length - 1; i++) {
|
|
if (characters[order[i]] > minCount) {
|
|
visibleItems.push(order[i]);
|
|
} else if (characters[order[i]] === minCount && minAllowed > 0) {
|
|
visibleItems.push(order[i]);
|
|
minAllowed--;
|
|
}
|
|
}
|
|
|
|
visibleItems.push(order[order.length - 1]);
|
|
|
|
this.setState({ visibleItems });
|
|
}
|
|
|
|
//
|
|
// Listeners
|
|
|
|
onMeasure = ({ height }) => {
|
|
this.setState({ height });
|
|
}
|
|
|
|
//
|
|
// Render
|
|
|
|
render() {
|
|
const {
|
|
minimumItems,
|
|
onItemPress
|
|
} = this.props;
|
|
|
|
const {
|
|
visibleItems
|
|
} = this.state;
|
|
|
|
if (!visibleItems.length || visibleItems.length < minimumItems) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className={styles.jumpBar}>
|
|
<Measure
|
|
whitelist={['height']}
|
|
onMeasure={this.onMeasure}
|
|
>
|
|
<div className={styles.jumpBarItems}>
|
|
{
|
|
visibleItems.map((item) => {
|
|
return (
|
|
<PageJumpBarItem
|
|
key={item}
|
|
label={item}
|
|
onItemPress={onItemPress}
|
|
/>
|
|
);
|
|
})
|
|
}
|
|
</div>
|
|
</Measure>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
PageJumpBar.propTypes = {
|
|
items: PropTypes.object.isRequired,
|
|
minimumItems: PropTypes.number.isRequired,
|
|
onItemPress: PropTypes.func.isRequired
|
|
};
|
|
|
|
PageJumpBar.defaultProps = {
|
|
minimumItems: 5
|
|
};
|
|
|
|
export default PageJumpBar;
|