'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

const index$2 = require('./index-30c1a2af.js');
const initialize = require('./initialize-0dc05a90.js');
const log = require('./log-83b06010.js');
const config_decorator = require('./config.decorator-25e5e66f.js');
const formInput = require('./form-input-2bb1eef5.js');
const helpers = require('./helpers-1c6c60eb.js');
const attributes = require('./attributes-53f7eb4c.js');
const index = require('./index-811956ed.js');
const index_esm = require('./index.esm-a8a77277.js');
const bem = require('./bem-5a880f9c.js');
const form = require('./form-0b7a0451.js');
const index$1 = require('./index-e6a233be.js');
const keys_constant = require('./keys.constant-222a72f4.js');
const index$3 = require('./index-d8c4556e.js');
require('./browser-c7d1d679.js');
require('./icons.constant-4a0e2fef.js');
require('./_commonjsHelpers-bcc1208a.js');

/**
 * lodash 3.0.2 (Custom Build) <https://lodash.com/>
 * Build: `lodash modularize exports="npm" -o ./`
 * Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/>
 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
 * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
 * Available under MIT license <https://lodash.com/license>
 */

/** `Object#toString` result references. */
var numberTag = '[object Number]';

/** Used for built-in method references. */
var objectProto = Object.prototype;

/**
 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
 * of values.
 */
var objectToString = objectProto.toString;

/**
 * Checks if `value` is object-like. A value is object-like if it's not `null`
 * and has a `typeof` result of "object".
 *
 * @static
 * @memberOf _
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
 * @example
 *
 * _.isObjectLike({});
 * // => true
 *
 * _.isObjectLike([1, 2, 3]);
 * // => true
 *
 * _.isObjectLike(_.noop);
 * // => false
 *
 * _.isObjectLike(null);
 * // => false
 */
function isObjectLike(value) {
  return !!value && typeof value == 'object';
}

/**
 * Checks if `value` is `NaN`.
 *
 * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4)
 * which returns `true` for `undefined` and other non-numeric values.
 *
 * @static
 * @memberOf _
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
 * @example
 *
 * _.isNaN(NaN);
 * // => true
 *
 * _.isNaN(new Number(NaN));
 * // => true
 *
 * isNaN(undefined);
 * // => true
 *
 * _.isNaN(undefined);
 * // => false
 */
function isNaN(value) {
  // An `NaN` primitive is the only value that is not equal to itself.
  // Perform the `toStringTag` check first to avoid errors with some ActiveX objects in IE.
  return isNumber$1(value) && value != +value;
}

/**
 * Checks if `value` is classified as a `Number` primitive or object.
 *
 * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified
 * as numbers, use the `_.isFinite` method.
 *
 * @static
 * @memberOf _
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
 * @example
 *
 * _.isNumber(3);
 * // => true
 *
 * _.isNumber(Number.MIN_VALUE);
 * // => true
 *
 * _.isNumber(Infinity);
 * // => true
 *
 * _.isNumber('3');
 * // => false
 */
function isNumber$1(value) {
  return typeof value == 'number' ||
    (isObjectLike(value) && objectToString.call(value) == numberTag);
}

var lodash_isnan = isNaN;

const getLocale = () => {
  const config = index.useBalConfig();
  return (config && config.locale) || initialize.defaultLocale;
};
const getDecimalSeparator = () => {
  return index_esm.getDecimalSeparator(getLocale());
};
const getThousandSeparator = () => {
  return index_esm.getThousandSeparator(getLocale());
};
const formatLocaleNumber = (number, minimumFractionDigits) => {
  return index_esm.formatLocaleNumber(getLocale(), number, minimumFractionDigits);
};
const getNegativeSymbol = () => {
  return '-';
};

function isNumber(value) {
  const num = parseFloat(value);
  return typeof num === 'number' && !lodash_isnan(num);
}
function isNotNumber(value) {
  return !isNumber(value) && value !== '' && value !== getNegativeSymbol() && value !== getDecimalSeparator();
}
function toNumber(value, decimalPoints = 0) {
  if (value === '' ||
    value === undefined ||
    value === null ||
    lodash_isnan(value) ||
    value === getNegativeSymbol() ||
    value === getDecimalSeparator() ||
    !isNumber(value)) {
    return undefined;
  }
  return decimalPoints === 0 ? parseInt(value, 10) : parseFloat(value);
}
function toFixedNumber(value, decimalPoints = 0) {
  if (index$1.lodash_isnil(value)) {
    return '';
  }
  if (value.charAt(0) === getDecimalSeparator()) {
    value = `0${value}`;
  }
  const num = decimalPoints === 0 ? parseInt(value, 10) : parseFloat(value.replace(getDecimalSeparator(), '.'));
  return lodash_isnan(num) ? '' : num.toFixed(decimalPoints);
}
function mapDecimalSeparator(value) {
  return value.replace('.', getDecimalSeparator());
}
function toUserFormattedNumber(value, decimalPoints = 0, suffix = '') {
  if (index$1.lodash_isnil(value)) {
    return '';
  }
  if (value.charAt(0) === getDecimalSeparator()) {
    value = `0${value}`;
  }
  const num = decimalPoints === 0 ? parseInt(value, 10) : parseFloat(value);
  const formattedSuffix = suffix !== '' ? ` ${suffix.trim()}` : '';
  return lodash_isnan(num) ? '' : formatLocaleNumber(num, decimalPoints) + formattedSuffix;
}
const countDecimalSeparators = (value) => (value.split(getDecimalSeparator()) || []).length - 1 || 0;
function validateKeyDown({ key, selectionStart, selectionEnd, newValue, decimal, }) {
  if (key === getNegativeSymbol() && selectionStart && selectionStart > 0 && selectionEnd && selectionEnd > 0) {
    return false;
  }
  if (key === getDecimalSeparator()) {
    if (decimal === 0) {
      return false;
    }
    else if (countDecimalSeparators(newValue) > 1) {
      return false;
    }
  }
  if (![...keys_constant.NUMBER_KEYS, ...keys_constant.ACTION_KEYS, getDecimalSeparator(), getNegativeSymbol()].includes(key)) {
    return false;
  }
  if (decimal !== 0 && newValue.includes(getDecimalSeparator()) && [...keys_constant.NUMBER_KEYS].includes(key)) {
    const newValueParts = newValue.split(getDecimalSeparator());
    const decimalPart = newValueParts[newValueParts.length - 1];
    if (decimalPart.length > decimal) {
      return false;
    }
  }
  return true;
}

const balNumberInputCss = ".bal-number-input{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:block;position:relative;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;width:100%;padding:0;font-family:var(--bal-font-family-text)}";

var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators, target, key, desc);
  else
    for (var i = decorators.length - 1; i >= 0; i--)
      if (d = decorators[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const NumberInput = class {
  constructor(hostRef) {
    index$2.registerInstance(this, hostRef);
    this.balInput = index$2.createEvent(this, "balInput", 7);
    this.balChange = index$2.createEvent(this, "balChange", 7);
    this.balBlur = index$2.createEvent(this, "balBlur", 7);
    this.balFocus = index$2.createEvent(this, "balFocus", 7);
    this.balKeyPress = index$2.createEvent(this, "balKeyPress", 7);
    this.inputId = `bal-number-input-${numberInputIds++}`;
    this.inheritedAttributes = {};
    this.lastValue = '';
    this.inputValue = this.value;
    this.initialValue = undefined;
    this.onClick = (ev) => formInput.inputHandleClick(this, ev);
    this.handleClick = (ev) => formInput.inputHandleHostClick(this, ev);
    this.onInput = (_ev) => {
      var _a;
      if (this.nativeInput) {
        if (isNotNumber(this.nativeInput.value)) {
          this.nativeInputValue = this.lastValue || '';
          return;
        }
      }
      this.lastValue = ((_a = this.nativeInput) === null || _a === void 0 ? void 0 : _a.value) || '';
      this.balInput.emit(toNumber(this.lastValue, this.decimal));
    };
    this.onFocus = (ev) => {
      formInput.inputHandleFocus(this, ev);
      if (this.nativeInput) {
        this.nativeInputValue = mapDecimalSeparator(this.lastValue || '');
      }
    };
    this.onBlur = (ev) => {
      formInput.inputHandleBlur(this, ev);
      if (this.nativeInput) {
        this.lastValue = toFixedNumber(this.lastValueGetter, this.decimal);
        this.nativeInputValue = toUserFormattedNumber(this.lastValueGetter, this.decimal, this.suffix);
      }
      this.inputValue = toNumber(this.lastValueGetter, this.decimal);
      formInput.inputHandleChange(this);
    };
    this.onKeydown = (ev) => {
      const oldValue = formInput.getNativeInputValue(this);
      const newValue = formInput.getUpcomingValue(this, ev);
      const input = ev === null || ev === void 0 ? void 0 : ev.target;
      if (input &&
        !validateKeyDown({
          key: ev.key,
          decimal: this.decimal,
          newValue,
          oldValue,
          selectionStart: input.selectionStart,
          selectionEnd: input.selectionEnd,
        })) {
        return formInput.stopEventBubbling(ev);
      }
    };
    this.focused = false;
    this.language = initialize.defaultConfig.language;
    this.region = initialize.defaultConfig.region;
    this.ariaForm = form.defaultBalAriaForm;
    this.nativeInputValue = '';
    this.inputPattern = this.createPattern();
    this.name = this.inputId;
    this.invalid = false;
    this.decimal = 0;
    this.suffix = undefined;
    this.pattern = undefined;
    this.placeholder = undefined;
    this.required = false;
    this.disabled = false;
    this.readonly = false;
    this.exactNumber = false;
    this.max = undefined;
    this.min = undefined;
    this.debounce = 0;
    this.value = undefined;
  }
  createLogger(log) {
    this.log = log;
  }
  debounceChanged() {
    this.balChange = helpers.debounceEvent(this.balChange, this.debounce);
  }
  valueChanged(newValue, oldValue) {
    if (newValue !== oldValue) {
      const isValueNotDefined = newValue === '' || index$1.lodash_isnil(newValue) || lodash_isnan(newValue);
      const emptyValue = this.exactNumber ? '0' : '';
      const value = isValueNotDefined ? emptyValue : newValue.toString();
      this.inputValue = toNumber(toFixedNumber(value, this.decimal), this.decimal);
      this.lastValue = toFixedNumber(value, this.decimal);
      if (this.focused) {
        this.nativeInputValue = mapDecimalSeparator(this.lastValue);
      }
      else {
        this.nativeInputValue = toUserFormattedNumber(this.lastValue, this.decimal, this.suffix);
      }
    }
  }
  connectedCallback() {
    this.debounceChanged();
    this.initialValue = this.value || 0;
    if (this.value !== undefined) {
      this.valueChanged(this.value, undefined);
    }
  }
  componentDidLoad() {
    this.inputValue = this.value;
  }
  componentWillLoad() {
    this.inheritedAttributes = attributes.inheritAttributes(this.el, ['aria-label', 'tabindex', 'title']);
  }
  listenOnClick(ev) {
    formInput.inputListenOnClick(this, ev);
  }
  resetHandler(ev) {
    const formElement = ev.target;
    if (formElement === null || formElement === void 0 ? void 0 : formElement.contains(this.el)) {
      formInput.inputHandleReset(this, this.initialValue, this.resetHandlerTimer);
    }
  }
  async configChanged(state) {
    this.language = state.language;
    this.region = state.region;
    this.inputPattern = this.createPattern();
    if (this.nativeInput) {
      if (this.focused) {
        this.nativeInputValue = mapDecimalSeparator(this.lastValue);
      }
      else {
        this.nativeInputValue = toUserFormattedNumber(this.lastValue, this.decimal, this.suffix);
      }
    }
  }
  async setFocus() {
    formInput.inputSetFocus(this);
  }
  async setBlur() {
    formInput.inputSetBlur(this);
  }
  getInputElement() {
    return Promise.resolve(this.nativeInput);
  }
  async setAriaForm(ariaForm) {
    this.ariaForm = Object.assign({}, ariaForm);
  }
  createPattern() {
    if (this.pattern) {
      return this.pattern;
    }
    let suffix = this.suffix || '';
    if (suffix !== '') {
      suffix = ` ${suffix}`;
    }
    const thousandSeparator = getThousandSeparator();
    let decimalSeparator = getDecimalSeparator();
    if (decimalSeparator === ',') {
      decimalSeparator = '\\,';
    }
    return `-?\\d{1,3}(?:${thousandSeparator}\\d{3})*(?:\\${decimalSeparator}\\d{1,2})?(?:${suffix})?`;
  }
  get lastValueGetter() {
    if (this.exactNumber && (index$1.lodash_isnil(this.lastValue) || index$3.lodash_isempty(this.lastValue))) {
      return '0';
    }
    return this.lastValue;
  }
  render() {
    const block = bem.BEM.block('number-input');
    return (index$2.h(index$2.Host, { onClick: this.handleClick, "aria-disabled": this.disabled ? 'true' : null, class: Object.assign({}, block.class()) }, index$2.h("input", Object.assign({ class: {
        'input': true,
        'is-disabled': this.disabled || this.readonly,
        'is-danger': this.invalid,
      }, "data-testid": "bal-number-input", ref: input => (this.nativeInput = input), id: this.ariaForm.controlId || this.inputId, "aria-labelledby": this.ariaForm.labelId, "aria-describedby": this.ariaForm.messageId, "aria-invalid": this.invalid === true ? 'true' : 'false', "aria-disabled": this.disabled ? 'true' : null, name: this.name, disabled: this.disabled, placeholder: this.placeholder || '', readonly: this.readonly, required: this.required, pattern: this.inputPattern, min: this.min, max: this.max, value: this.nativeInputValue, onInput: e => this.onInput(e), onFocus: e => this.onFocus(e), onBlur: e => this.onBlur(e), onClick: this.onClick, onKeyDown: e => this.onKeydown(e), onKeyPress: e => this.balKeyPress.emit(e) }, this.inheritedAttributes))));
  }
  get el() { return index$2.getElement(this); }
  static get watchers() { return {
    "debounce": ["debounceChanged"],
    "value": ["valueChanged"]
  }; }
};
__decorate([
  log.Logger('bal-number-input')
], NumberInput.prototype, "createLogger", null);
__decorate([
  config_decorator.ListenToConfig()
], NumberInput.prototype, "configChanged", null);
let numberInputIds = 0;
NumberInput.style = {
  css: balNumberInputCss
};

exports.bal_number_input = NumberInput;
