<commit_before>import React, { cloneElement } from "react";
import PropTypes from "prop-types";
import cx from "classnames";
import { Label } from "../Label";
import { TextField } from "../TextField";
import { Option } from "../Option";
import { utils } from "../utils";
import matchSorter from "match-sorter";
import CSSModules from "react-css-modules";
import styles from "./Dropdown.css";

export class Dropdown extends React.PureComponent {
  constructor(props) {
    super(props);

    this.menuRef = React.createRef();
    this.hoverRef = React.createRef();

    const data = this.setOptions({}, props);

    this.state = {
      "active": false, // Whether or not the options are visible
      "display": data.display, // The text to be displayed for the selected option
      "focus": false, // Whether or not the Dropdown has the browser's focus
      "message": props.message || null, // Used for error handling
      "options": data.options, // The available options for the Dropdown
      "selectedIndex": data.selectedIndex, // The index of the currently selected option within the rendered options list
      "status": props.status || null, // Used for error handling
      "tempIndex": null, // Used to keep track of which option is in a "hover" state, either by mouseOver or through keyboard navigation of an active Dropdown
      "value": props.value // The actual value to submit to the form for the selected option
    };
  }

  // Watching to see if the user updates the list of options or the selected value. If they do, re-render the Dropdown accordingly
  componentWillReceiveProps(nextProps) {
    if (
      typeof nextProps.options !== "undefined" &&
        nextProps.options !== this.props.options ||
      typeof nextProps.children !== "undefined" &&
        typeof nextProps.options === "undefined" &&
        nextProps.children !== this.props.children ||
      nextProps.value !== this.props.value
    ) {
      const data = this.setOptions({}, nextProps, false, true);
      this.setState({
        "options": data.options,
        "display": data.display,
        "value": nextProps.value
      });
    }
    if (
      typeof nextProps.status !== "undefined" &&
        nextProps.status !== this.props.status ||
      typeof nextProps.message !== "undefined" &&
        nextProps.message !== this.props.message
    ) {
      this.setState({
        "status": nextProps.status,
        "message": nextProps.message
      });
    }
  }

  // the function was used for keyboard scrolling in dropdown menus
  componentDidUpdate() {
    const menuNode = this.menuRef.current;

    if (this.hoverRef.current !== null) {
      // keyboard scrolls takes options in view
      const optionNode = this.hoverRef.current.optionDivRef.current;

      const menuTop = menuNode.scrollTop;
      const menuBottom = menuTop + menuNode.offsetHeight;
      const optionTop = optionNode.offsetTop;
      const optionBottom = optionTop + optionNode.offsetHeight;

      if (menuTop > optionTop || menuBottom < optionBottom) {
        menuNode.scrollTop = optionNode.offsetTop;
      }

      if (menuBottom < optionBottom) {
        menuNode.scrollTop =
          optionNode.offsetTop +
          optionNode.clientHeight -
          menuNode.offsetHeight;
      } else if (menuTop > optionTop) {
        menuNode.scrollTop = optionNode.offsetTop;
      }
    }
  }

  /**
   * The function used to render or update the options list
   * Checks for data vs. children, assigns a special prop to the selected option, and determines value and display text of selected item
   */
  setOptions(updatedValues, props, filter, propChange, viaIndex) {
    let returnDisplay = "";
    let returnValue = "";
    let valueFound = false;
    let selectedIndex = null;
    // Check the known display text to get the option's value
    const checkDisplay = (display, value) => {
      if (
        typeof updatedValues.display !== "undefined" &&
        updatedValues.display === display
      ) {
        valueFound = true;
        return value;
      } else {
        return "";<commit_msg>this fixes #810; dropdown menu is fully visible when expanded (#812)<commit_after>import React, { cloneElement } from "react";
import PropTypes from "prop-types";
import cx from "classnames";
import { Label } from "../Label";
import { TextField } from "../TextField";
import { Option } from "../Option";
import { utils } from "../utils";
import matchSorter from "match-sorter";
import CSSModules from "react-css-modules";
import styles from "./Dropdown.css";

export class Dropdown extends React.PureComponent {
  constructor(props) {
    super(props);

    this.menuRef = React.createRef();
    this.hoverRef = React.createRef();

    const data = this.setOptions({}, props);

    this.state = {
      "active": false, // Whether or not the options are visible
      "display": data.display, // The text to be displayed for the selected option
      "focus": false, // Whether or not the Dropdown has the browser's focus
      "message": props.message || null, // Used for error handling
      "options": data.options, // The available options for the Dropdown
      "selectedIndex": data.selectedIndex, // The index of the currently selected option within the rendered options list
      "status": props.status || null, // Used for error handling
      "tempIndex": null, // Used to keep track of which option is in a "hover" state, either by mouseOver or through keyboard navigation of an active Dropdown
      "value": props.value // The actual value to submit to the form for the selected option
    };
  }

  // Watching to see if the user updates the list of options or the selected value. If they do, re-render the Dropdown accordingly
  componentWillReceiveProps(nextProps) {
    if (
      typeof nextProps.options !== "undefined" &&
        nextProps.options !== this.props.options ||
      typeof nextProps.children !== "undefined" &&
        typeof nextProps.options === "undefined" &&
        nextProps.children !== this.props.children ||
      nextProps.value !== this.props.value
    ) {
      const data = this.setOptions({}, nextProps, false, true);
      this.setState({
        "options": data.options,
        "display": data.display,
        "value": nextProps.value
      });
    }
    if (
      typeof nextProps.status !== "undefined" &&
        nextProps.status !== this.props.status ||
      typeof nextProps.message !== "undefined" &&
        nextProps.message !== this.props.message
    ) {
      this.setState({
        "status": nextProps.status,
        "message": nextProps.message
      });
    }
  }

  // the function was used for keyboard scrolling in dropdown menus
  componentDidUpdate() {
    const menuNode = this.menuRef.current;

    if (this.hoverRef.current !== null) {
      // keyboard scrolls takes options in view
      const optionNode = this.hoverRef.current.optionDivRef.current;

      const menuTop = menuNode.scrollTop;
      const menuBottom = menuTop + menuNode.offsetHeight;
      const optionTop = optionNode.offsetTop;
      const optionBottom = optionTop + optionNode.offsetHeight;

      if (menuTop > optionTop || menuBottom < optionBottom) {
        menuNode.scrollTop = optionNode.offsetTop;
      }

      if (menuBottom < optionBottom) {
        menuNode.scrollTop =
          optionNode.offsetTop +
          optionNode.clientHeight -
          menuNode.offsetHeight;
      } else if (menuTop > optionTop) {
        menuNode.scrollTop = optionNode.offsetTop;
      }
    }

    // Drop options menu should be fully visible in view when expanded
    const menuRect = menuNode.getBoundingClientRect();
    if (window.innerHeight < menuRect.bottom) {
      window.scrollBy(0, menuRect.bottom - window.innerHeight);
    }
  }

  /**
   * The function used to render or update the options list
   * Checks for data vs. children, assigns a special prop to the selected option, and determines value and display text of selected item
   */
  setOptions(updatedValues, props, filter, propChange, viaIndex) {
    let returnDisplay = "";
    let returnValue = "";
    let valueFound = false;
    let selectedIndex = null;
    // Check the known display text to get the option's value
    const checkDisplay = (display, value) => {
      if (
        typeof updatedValues.display !== "undefined" &&
        updatedValues.display === display
      ) {
        valueFound = true;
        return value;
      } else {
        return "";
{'fraction_non_alphanumeric': 0.10674687426279783, 'fraction_numerical': 0.0008256664307619722, 'mean_word_length': 2.766770324300311, 'pattern_counts': {'":': 28, '<': 8, '<?xml version=': 0, '>': 9, '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': '6404355', 'n_tokens_mistral': 2233, 'n_tokens_neox': 2199, 'n_words': 758}