<commit_before>import PropTypes from 'prop-types';
import React, { Component } from 'react';
import {
  childrenPropType,
  onSelectPropType,
  selectedIndexPropType,
} from '../helpers/propTypes';
import UncontrolledTabs from './UncontrolledTabs';
import { getTabsCount } from '../helpers/count';

const MODE_CONTROLLED = 0;
const MODE_UNCONTROLLED = 1;

export default class Tabs extends Component {
  static defaultProps = {
    defaultFocus: false,
    forceRenderTabPanel: false,
    selectedIndex: null,
    defaultIndex: null,
    environment: null,
    disableUpDownKeys: false,
  };

  static propTypes = {
    children: childrenPropType,
    direction: PropTypes.oneOf(['rtl', 'ltr']),
    className: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.array,
      PropTypes.object,
    ]),
    defaultFocus: PropTypes.bool,
    defaultIndex: PropTypes.number,
    disabledTabClassName: PropTypes.string,
    disableUpDownKeys: PropTypes.bool,
    domRef: PropTypes.func,
    forceRenderTabPanel: PropTypes.bool,
    onSelect: onSelectPropType,
    selectedIndex: selectedIndexPropType,
    selectedTabClassName: PropTypes.string,
    selectedTabPanelClassName: PropTypes.string,
    environment: PropTypes.object,
  };

  constructor(props) {
    super(props);

    this.state = Tabs.copyPropsToState(this.props, {}, props.defaultFocus);
  }

  static getDerivedStateFromProps(props, state) {
    return Tabs.copyPropsToState(props, state);
  }

  static getModeFromProps(props) {
    return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED;
  }

  handleSelected = (index, last, event) => {
    const { onSelect } = this.props;
    const { mode } = this.state;

    // Call change event handler
    if (typeof onSelect === 'function') {
      // Check if the change event handler cancels the tab change
      if (onSelect(index, last, event) === false) return;
    }

    const state = {
      // Set focus if the change was triggered from the keyboard
      focus: event.type === 'keydown',
    };

    if (mode === MODE_UNCONTROLLED) {
      // Update selected index
      state.selectedIndex = index;
    }

    this.setState(state);
  };

  // preserve the existing selectedIndex from state.
  // If the state has not selectedIndex, default to the defaultIndex or 0
  static copyPropsToState(props, state, focus = false) {
    if (
      process.env.NODE_ENV !== 'production' &&
      state.mode !== undefined &&
      state.mode !== Tabs.getModeFromProps(props)
    ) {
      throw new Error(
        `Switching between controlled mode (by using \`selectedIndex\`) and uncontrolled mode is not supported in \`Tabs\`.
For more information about controlled and uncontrolled mode of react-tabs see the README.`,
      );
    }

    const newState = {
      focus,
      mode: Tabs.getModeFromProps(props),
    };

    if (newState.mode === MODE_UNCONTROLLED) {
      const maxTabIndex = Math.max(0, getTabsCount(props.children) - 1);
      let selectedIndex = null;

      if (state.selectedIndex != null) {
        selectedIndex = Math.min(state.selectedIndex, maxTabIndex);
      } else {
        selectedIndex = props.defaultIndex || 0;
      }
      newState.selectedIndex = selectedIndex;<commit_msg>fix: Add link to error message about controlled vs uncontrolled<commit_after>import PropTypes from 'prop-types';
import React, { Component } from 'react';
import {
  childrenPropType,
  onSelectPropType,
  selectedIndexPropType,
} from '../helpers/propTypes';
import UncontrolledTabs from './UncontrolledTabs';
import { getTabsCount } from '../helpers/count';

const MODE_CONTROLLED = 0;
const MODE_UNCONTROLLED = 1;

export default class Tabs extends Component {
  static defaultProps = {
    defaultFocus: false,
    forceRenderTabPanel: false,
    selectedIndex: null,
    defaultIndex: null,
    environment: null,
    disableUpDownKeys: false,
  };

  static propTypes = {
    children: childrenPropType,
    direction: PropTypes.oneOf(['rtl', 'ltr']),
    className: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.array,
      PropTypes.object,
    ]),
    defaultFocus: PropTypes.bool,
    defaultIndex: PropTypes.number,
    disabledTabClassName: PropTypes.string,
    disableUpDownKeys: PropTypes.bool,
    domRef: PropTypes.func,
    forceRenderTabPanel: PropTypes.bool,
    onSelect: onSelectPropType,
    selectedIndex: selectedIndexPropType,
    selectedTabClassName: PropTypes.string,
    selectedTabPanelClassName: PropTypes.string,
    environment: PropTypes.object,
  };

  constructor(props) {
    super(props);

    this.state = Tabs.copyPropsToState(this.props, {}, props.defaultFocus);
  }

  static getDerivedStateFromProps(props, state) {
    return Tabs.copyPropsToState(props, state);
  }

  static getModeFromProps(props) {
    return props.selectedIndex === null ? MODE_UNCONTROLLED : MODE_CONTROLLED;
  }

  handleSelected = (index, last, event) => {
    const { onSelect } = this.props;
    const { mode } = this.state;

    // Call change event handler
    if (typeof onSelect === 'function') {
      // Check if the change event handler cancels the tab change
      if (onSelect(index, last, event) === false) return;
    }

    const state = {
      // Set focus if the change was triggered from the keyboard
      focus: event.type === 'keydown',
    };

    if (mode === MODE_UNCONTROLLED) {
      // Update selected index
      state.selectedIndex = index;
    }

    this.setState(state);
  };

  // preserve the existing selectedIndex from state.
  // If the state has not selectedIndex, default to the defaultIndex or 0
  static copyPropsToState(props, state, focus = false) {
    if (
      process.env.NODE_ENV !== 'production' &&
      state.mode !== undefined &&
      state.mode !== Tabs.getModeFromProps(props)
    ) {
      throw new Error(
        `Switching between controlled mode (by using \`selectedIndex\`) and uncontrolled mode is not supported in \`Tabs\`.
For more information about controlled and uncontrolled mode of react-tabs see https://github.com/reactjs/react-tabs#controlled-vs-uncontrolled-mode.`,
      );
    }

    const newState = {
      focus,
      mode: Tabs.getModeFromProps(props),
    };

    if (newState.mode === MODE_UNCONTROLLED) {
      const maxTabIndex = Math.max(0, getTabsCount(props.children) - 1);
      let selectedIndex = null;

      if (state.selectedIndex != null) {
        selectedIndex = Math.min(state.selectedIndex, maxTabIndex);
      } else {
        selectedIndex = props.defaultIndex || 0;
      }
      newState.selectedIndex = selectedIndex;
{'fraction_non_alphanumeric': 0.10628311884935655, 'fraction_numerical': 0.0018168054504163512, 'mean_word_length': 3.218390804597701, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 1, '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': '7021446', 'n_tokens_mistral': 1917, 'n_tokens_neox': 1917, 'n_words': 503}