<commit_before>/**
 * Copyright IBM Corp. 2016, 2018
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import PropTypes from 'prop-types';
import React, { Component } from 'react';
import classNames from 'classnames';
import { settings } from 'carbon-components';
import {
  WarningFilled16,
  CaretDownGlyph,
  CaretUpGlyph,
} from '@carbon/icons-react';
import mergeRefs from '../../tools/mergeRefs';
import requiredIfValueExists from '../../prop-types/requiredIfValueExists';
import { useControlledStateWithValue } from '../../internal/FeatureFlags';

const { prefix } = settings;

export const translationIds = {
  'increment.number': 'increment.number',
  'decrement.number': 'decrement.number',
};

const defaultTranslations = {
  [translationIds['increment.number']]: 'Increment number',
  [translationIds['decrement.number']]: 'Decrement number',
};

const capMin = (min, value) =>
  isNaN(min) || (!min && min !== 0) || isNaN(value) || (!value && value !== 0)
    ? value
    : Math.max(min, value);
const capMax = (max, value) =>
  isNaN(max) || (!max && max !== 0) || isNaN(value) || (!value && value !== 0)
    ? value
    : Math.min(max, value);

class NumberInput extends Component {
  static propTypes = {
    /**
     * Specify an optional className to be applied to the wrapper node
     */
    className: PropTypes.string,
    /**
     * Specify if the control should be disabled, or not
     */
    disabled: PropTypes.bool,
    /**
     * Specify whether you want the underlying label to be visually hidden
     */
    hideLabel: PropTypes.bool,
    /**
     * Provide a description for up/down icons that can be read by screen readers
     */
    iconDescription: PropTypes.string.isRequired,
    /**
     * Specify a custom `id` for the input
     */
    id: PropTypes.string.isRequired,
    /**
     * Generic `label` that will be used as the textual representation of what
     * this field is for
     */
    label: PropTypes.node,
    /**
     * The maximum value.
     */
    max: PropTypes.number,
    /**
     * The minimum value.
     */
    min: PropTypes.number,
    /**
     * The new value is available in 'imaginaryTarget.value'
     * i.e. to get the value: evt.imaginaryTarget.value
     *
     * * _With_ `useControlledStateWithValue` feature flag, the signature of the event handler will be altered to provide additional context in the second parameter: `onChange(event, { value, direction })` where:
     *   * `event` is the (React) raw event
     *   * `value` is the new value
     *   * `direction` tells you the button you hit is up button or down button
     * * _Without_ this feature flag the event handler has `onChange(event, direction)` signature.
     */
    onChange: !useControlledStateWithValue
      ? PropTypes.func
      : requiredIfValueExists(PropTypes.func),
    /**
     * Provide an optional function to be called when the up/down button is clicked
     */
    onClick: PropTypes.func,
    /**
     * Specify how much the valus should increase/decrease upon clicking on up/down button
     */
    step: PropTypes.number,
    /**
     * Optional starting value for uncontrolled state
     */
    defaultValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    /**
     * Specify the value of the input
     */
    value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    /**
     * Specify if the component should be read-only
     */
    readOnly: PropTypes.bool,
    /**
     * Specify if the currently value is invalid.
     */
    invalid: PropTypes.bool,
    /**
     * Message which is displayed if the value is invalid.
     */
    invalidText: PropTypes.string,
    /**
     * Provide text that is used alongside the control label for additional help
     */
    helperText: PropTypes.node,
    /**
     * Provide a description that would be used to best describe the use case of the NumberInput component
     */
    ariaLabel: PropTypes.string,
    /**
     * `true` to use the light version.
     */
    light: PropTypes.bool,
    /**
     * `true` to allow empty string.
     */
    allowEmpty: PropTypes.bool,
    /**
     * Provide custom text for the component for each translation id
     */
    translateWithId: PropTypes.func.isRequired,
    /**
     * `true` to use the mobile variant.
     */
    isMobile: PropTypes.bool,
  };

  static defaultProps = {
    disabled: false,
    hideLabel: false,
    iconDescription: 'choose a number',
    label: ' ',
    step: 1,
    invalid: false,
    invalidText: 'Provide invalidText',
    ariaLabel: 'Numeric input field with increment and decrement buttons',
    helperText: '',
    light: false,
    allowEmpty: false,
    translateWithId: id => defaultTranslations[id],
  };

  static getDerivedStateFromProps({ min, max, value = 0 }, state) {
    const { prevValue } = state;

    if (useControlledStateWithValue && value === '' && prevValue !== '') {
      return {
        value: '',
        prevValue: '',
      };
    }

    // If `useControlledStateWithValue` feature flag is on, do nothing here.
    // Otherwise, do prop -> state sync with "value capping".
    return useControlledStateWithValue || prevValue === value
      ? null
      : {
          value: capMax(max, capMin(min, value)),
          prevValue: value,<commit_msg>fix(number-input): remove default value for label (#5347)<commit_after>/**
 * Copyright IBM Corp. 2016, 2018
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import PropTypes from 'prop-types';
import React, { Component } from 'react';
import classNames from 'classnames';
import { settings } from 'carbon-components';
import {
  WarningFilled16,
  CaretDownGlyph,
  CaretUpGlyph,
} from '@carbon/icons-react';
import mergeRefs from '../../tools/mergeRefs';
import requiredIfValueExists from '../../prop-types/requiredIfValueExists';
import { useControlledStateWithValue } from '../../internal/FeatureFlags';

const { prefix } = settings;

export const translationIds = {
  'increment.number': 'increment.number',
  'decrement.number': 'decrement.number',
};

const defaultTranslations = {
  [translationIds['increment.number']]: 'Increment number',
  [translationIds['decrement.number']]: 'Decrement number',
};

const capMin = (min, value) =>
  isNaN(min) || (!min && min !== 0) || isNaN(value) || (!value && value !== 0)
    ? value
    : Math.max(min, value);
const capMax = (max, value) =>
  isNaN(max) || (!max && max !== 0) || isNaN(value) || (!value && value !== 0)
    ? value
    : Math.min(max, value);

class NumberInput extends Component {
  static propTypes = {
    /**
     * Specify an optional className to be applied to the wrapper node
     */
    className: PropTypes.string,
    /**
     * Specify if the control should be disabled, or not
     */
    disabled: PropTypes.bool,
    /**
     * Specify whether you want the underlying label to be visually hidden
     */
    hideLabel: PropTypes.bool,
    /**
     * Provide a description for up/down icons that can be read by screen readers
     */
    iconDescription: PropTypes.string.isRequired,
    /**
     * Specify a custom `id` for the input
     */
    id: PropTypes.string.isRequired,
    /**
     * Generic `label` that will be used as the textual representation of what
     * this field is for
     */
    label: PropTypes.node,
    /**
     * The maximum value.
     */
    max: PropTypes.number,
    /**
     * The minimum value.
     */
    min: PropTypes.number,
    /**
     * The new value is available in 'imaginaryTarget.value'
     * i.e. to get the value: evt.imaginaryTarget.value
     *
     * * _With_ `useControlledStateWithValue` feature flag, the signature of the event handler will be altered to provide additional context in the second parameter: `onChange(event, { value, direction })` where:
     *   * `event` is the (React) raw event
     *   * `value` is the new value
     *   * `direction` tells you the button you hit is up button or down button
     * * _Without_ this feature flag the event handler has `onChange(event, direction)` signature.
     */
    onChange: !useControlledStateWithValue
      ? PropTypes.func
      : requiredIfValueExists(PropTypes.func),
    /**
     * Provide an optional function to be called when the up/down button is clicked
     */
    onClick: PropTypes.func,
    /**
     * Specify how much the valus should increase/decrease upon clicking on up/down button
     */
    step: PropTypes.number,
    /**
     * Optional starting value for uncontrolled state
     */
    defaultValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    /**
     * Specify the value of the input
     */
    value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    /**
     * Specify if the component should be read-only
     */
    readOnly: PropTypes.bool,
    /**
     * Specify if the currently value is invalid.
     */
    invalid: PropTypes.bool,
    /**
     * Message which is displayed if the value is invalid.
     */
    invalidText: PropTypes.string,
    /**
     * Provide text that is used alongside the control label for additional help
     */
    helperText: PropTypes.node,
    /**
     * Provide a description that would be used to best describe the use case of the NumberInput component
     */
    ariaLabel: PropTypes.string,
    /**
     * `true` to use the light version.
     */
    light: PropTypes.bool,
    /**
     * `true` to allow empty string.
     */
    allowEmpty: PropTypes.bool,
    /**
     * Provide custom text for the component for each translation id
     */
    translateWithId: PropTypes.func.isRequired,
    /**
     * `true` to use the mobile variant.
     */
    isMobile: PropTypes.bool,
  };

  static defaultProps = {
    disabled: false,
    hideLabel: false,
    iconDescription: 'choose a number',
    step: 1,
    invalid: false,
    invalidText: 'Provide invalidText',
    ariaLabel: 'Numeric input field with increment and decrement buttons',
    helperText: '',
    light: false,
    allowEmpty: false,
    translateWithId: id => defaultTranslations[id],
  };

  static getDerivedStateFromProps({ min, max, value = 0 }, state) {
    const { prevValue } = state;

    if (useControlledStateWithValue && value === '' && prevValue !== '') {
      return {
        value: '',
        prevValue: '',
      };
    }

    // If `useControlledStateWithValue` feature flag is on, do nothing here.
    // Otherwise, do prop -> state sync with "value capping".
    return useControlledStateWithValue || prevValue === value
      ? null
      : {
          value: capMax(max, capMin(min, value)),
          prevValue: value,
{'fraction_non_alphanumeric': 0.11534185658699278, 'fraction_numerical': 0.0037057624606262737, 'mean_word_length': 2.7108972155379853, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, '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': '7147306', 'n_tokens_mistral': 3066, 'n_tokens_neox': 3065, 'n_words': 1018}