<commit_before>import React from 'react'
import cx from 'classnames'
import { indexOf, isEmpty } from 'lodash'
import { getKeyCode, keyMap } from '../util/textInput'
var { array, func, object } = React.PropTypes

export default class KeyControlledList extends React.Component {

  static propTypes = {
    onChange: func.isRequired,
    items: array,
    selected: object
  }

  constructor (props) {
    super(props)
    let { items, selected } = props
    let index = indexOf(items, selected)
    this.state = {selectedIndex: index !== -1 ? index : 0}
  }

  componentWillReceiveProps (nextProps) {
    var max = nextProps.items.length - 1
    if (this.state.selectedIndex > max) {
      this.setState({selectedIndex: max})
    }
  }

  changeSelection = delta => {
    if (isEmpty(this.props.items)) return

    var i = this.state.selectedIndex
    var length = this.props.items.length

    i += delta
    if (i < 0) i += length
    i = i % length

    this.setState({selectedIndex: i})
  }

  // this method is called from other components
  handleKeys = event => {
    switch (getKeyCode(event)) {
      case keyMap.UP:
        this.changeSelection(-1)
        return true
      case keyMap.DOWN:
        this.changeSelection(1)
        return true
      case keyMap.TAB:
      case keyMap.ENTER:
        if (!isEmpty(this.props.items)) {
          var choice = this.props.items[this.state.selectedIndex]
          this.change(choice, event)
        }
        return true
    }
  }

  change = (choice, event) => {
    event.preventDefault()
    this.props.onChange(choice, event)
  }

  // FIXME use more standard props e.g. {label, value} instead of {id, name}, or
  // provide an API for configuring them
  render () {
    let { selectedIndex } = this.state
    let { items, onChange, ...props } = this.props
    return <ul {...props}>
      {items.map((c, i) =>
        <li key={c.id || 'blank'} className={cx({active: selectedIndex === i})}>
          <a onClick={event => this.change(c, event)}>{c.name}</a>
        </li>)}
    </ul>
  }
}

export class GenericKeyControlledList extends React.Component {

  static propTypes = {
    onChange: func,
    children: array,
    selected: object<commit_msg>make KeyControlledList depend on GenericKeyControlledList<commit_after>import React from 'react'
import { indexOf, isEmpty } from 'lodash'
import { find } from 'lodash/fp'
import { getKeyCode, keyMap } from '../util/textInput'
var { array, func, object } = React.PropTypes

export default class KeyControlledList extends React.Component {

  static propTypes = {
    onChange: func.isRequired,
    items: array,
    selected: object
  }

  // this method is called from other components
  handleKeys = event => {
    this.refs.gkcl.handleKeys(event)
  }

  change = (choice, event) => {
    event.preventDefault()
    this.props.onChange(choice, event)
  }

  onChangeExtractingItem = (choice, event) => {
    const item = find(i => i.id === choice.key, this.props.items)
    this.change(item, event)
  }

  // FIXME use more standard props e.g. {label, value} instead of {id, name}, or
  // provide an API for configuring them
  render () {
    let { items, onChange, ...props } = this.props
    return <GenericKeyControlledList ref='gkcl'
      onChange={this.onChangeExtractingItem} {...props}>
      {items.map((c, i) =>
        <li key={c.id || 'blank'}>
          <a onClick={event => this.change(c, event)}>{c.name}</a>
        </li>)}
    </GenericKeyControlledList>
  }
}

export class GenericKeyControlledList extends React.Component {

  static propTypes = {
    onChange: func,
    children: array,
    selected: object
{'fraction_non_alphanumeric': 0.12870472008781558, 'fraction_numerical': 0.001646542261251372, 'mean_word_length': 2.800834202294056, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '912035', 'n_tokens_mistral': 1131, 'n_tokens_neox': 1119, 'n_words': 307}