"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = require("react");
var Label_1 = require("../../Label");
var Icon_1 = require("../../Icon");
var Utilities_1 = require("../../Utilities");
var getClassNames = Utilities_1.classNamesFunction();
var DEFAULT_STATE_VALUE = '';
var TextFieldBase = /** @class */ (function (_super) {
    tslib_1.__extends(TextFieldBase, _super);
    function TextFieldBase(props) {
        var _this = _super.call(this, props) || this;
        _this._textElement = Utilities_1.createRef();
        _this._onRenderLabel = function (props) {
            var label = props.label, required = props.required;
            // IProcessedStyleSet definition requires casting for what Label expects as its styles prop
            var labelStyles = _this._classNames.subComponentStyles
                ? _this._classNames.subComponentStyles.label
                : undefined;
            if (label) {
                return (React.createElement(Label_1.Label, { required: required, htmlFor: _this._id, styles: labelStyles }, props.label));
            }
            return null;
        };
        _this._onRenderDescription = function (props) {
            if (props.description) {
                return React.createElement("span", { className: _this._classNames.description }, props.description);
            }
            return null;
        };
        _this._warnDeprecations({
            iconClass: 'iconProps',
            addonString: 'prefix',
            onRenderAddon: 'onRenderPrefix',
            onChanged: 'onChange'
        });
        _this._warnMutuallyExclusive({
            value: 'defaultValue'
        });
        _this._id = props.id || Utilities_1.getId('TextField');
        _this._descriptionId = Utilities_1.getId('TextFieldDescription');
        if (props.value !== undefined) {
            _this._latestValue = props.value;
        }
        else if (props.defaultValue !== undefined) {
            _this._latestValue = props.defaultValue;
        }
        else {
            _this._latestValue = DEFAULT_STATE_VALUE;
        }
        _this.state = {
            value: _this._latestValue,
            isFocused: false,
            errorMessage: ''
        };
        _this._onInputChange = _this._onInputChange.bind(_this);
        _this._onFocus = _this._onFocus.bind(_this);
        _this._onBlur = _this._onBlur.bind(_this);
        _this._delayedValidate = _this._async.debounce(_this._validate, _this.props.deferredValidationTime);
        _this._lastValidation = 0;
        _this._isDescriptionAvailable = false;
        return _this;
    }
    Object.defineProperty(TextFieldBase.prototype, "value", {
        /**
         * Gets the current value of the text field.
         */
        get: function () {
            return this.state.value;
        },
        enumerable: true,
        configurable: true
    });
    TextFieldBase.prototype.componentDidMount = function () {
        this._isMounted = true;
        this._adjustInputHeight();
        if (this.props.validateOnLoad) {
            this._validate(this.state.value);
        }
    };
    TextFieldBase.prototype.componentWillReceiveProps = function (newProps) {
        var onBeforeChange = this.props.onBeforeChange;
        // If old value prop was undefined, then component is controlled and we should
        //    respect new undefined value and update state accordingly.
        if (newProps.value !== this.state.value && (newProps.value !== undefined || this.props.value !== undefined)) {
            if (onBeforeChange) {
                onBeforeChange(newProps.value);
            }
            this._id = newProps.id || this._id;
            this._setValue(newProps.value);
            var validateOnFocusIn = newProps.validateOnFocusIn, validateOnFocusOut = newProps.validateOnFocusOut;
            if (!(validateOnFocusIn || validateOnFocusOut)) {
                this._delayedValidate(newProps.value);
            }
        }
        // If component is not currently controlled and defaultValue changes, set value to new defaultValue.
        if (newProps.defaultValue !== this.props.defaultValue && newProps.value === undefined) {
            this._setValue(newProps.defaultValue);
        }
    };
    TextFieldBase.prototype.componentWillUnmount = function () {
        this._isMounted = false;
    };
    TextFieldBase.prototype.render = function () {
        var _a = this.props, borderless = _a.borderless, className = _a.className, description = _a.description, disabled = _a.disabled, iconClass = _a.iconClass, iconProps = _a.iconProps, inputClassName = _a.inputClassName, label = _a.label, multiline = _a.multiline, required = _a.required, underlined = _a.underlined, addonString = _a.addonString, // @deprecated
        prefix = _a.prefix, resizable = _a.resizable, suffix = _a.suffix, theme = _a.theme, styles = _a.styles, _b = _a.onRenderAddon, onRenderAddon = _b === void 0 ? this._onRenderAddon : _b, // @deprecated
        _c = _a.onRenderPrefix, // @deprecated
        onRenderPrefix = _c === void 0 ? this._onRenderPrefix : _c, _d = _a.onRenderSuffix, onRenderSuffix = _d === void 0 ? this._onRenderSuffix : _d, _e = _a.onRenderLabel, onRenderLabel = _e === void 0 ? this._onRenderLabel : _e, _f = _a.onRenderDescription, onRenderDescription = _f === void 0 ? this._onRenderDescription : _f;
        var isFocused = this.state.isFocused;
        var errorMessage = this._errorMessage;
        this._classNames = getClassNames(styles, {
            theme: theme,
            className: className,
            disabled: disabled,
            focused: isFocused,
            required: required,
            multiline: multiline,
            hasLabel: !!label,
            hasErrorMessage: !!errorMessage,
            borderless: borderless,
            resizable: resizable,
            hasIcon: !!iconProps,
            underlined: underlined,
            iconClass: iconClass,
            inputClassName: inputClassName
        });
        // If a custom description render function is supplied then treat description as always available.
        // Otherwise defer to the presence of description or error message text.
        this._isDescriptionAvailable = Boolean(this.props.onRenderDescription || description || errorMessage);
        return (React.createElement("div", { className: this._classNames.root },
            React.createElement("div", { className: this._classNames.wrapper },
                onRenderLabel(this.props, this._onRenderLabel),
                React.createElement("div", { className: this._classNames.fieldGroup },
                    (addonString !== undefined || this.props.onRenderAddon) && (React.createElement("div", { className: this._classNames.prefix }, onRenderAddon(this.props, this._onRenderAddon))),
                    (prefix !== undefined || this.props.onRenderPrefix) && (React.createElement("div", { className: this._classNames.prefix }, onRenderPrefix(this.props, this._onRenderPrefix))),
                    multiline ? this._renderTextArea() : this._renderInput(),
                    (iconClass || iconProps) && React.createElement(Icon_1.Icon, tslib_1.__assign({ className: this._classNames.icon }, iconProps)),
                    (suffix !== undefined || this.props.onRenderSuffix) && (React.createElement("div", { className: this._classNames.suffix }, onRenderSuffix(this.props, this._onRenderSuffix))))),
            this._isDescriptionAvailable && (React.createElement("span", { id: this._descriptionId },
                onRenderDescription(this.props, this._onRenderDescription),
                errorMessage && (React.createElement("div", { role: "alert" },
                    React.createElement(Utilities_1.DelayedRender, null,
                        React.createElement("p", { className: this._classNames.errorMessage },
                            React.createElement("span", { "data-automation-id": "error-message" }, errorMessage)))))))));
    };
    /**
     * Sets focus on the text field
     */
    TextFieldBase.prototype.focus = function () {
        if (this._textElement.current) {
            this._textElement.current.focus();
        }
    };
    /**
     * Blurs the text field.
     */
    TextFieldBase.prototype.blur = function () {
        if (this._textElement.current) {
            this._textElement.current.blur();
        }
    };
    /**
     * Selects the text field
     */
    TextFieldBase.prototype.select = function () {
        if (this._textElement.current) {
            this._textElement.current.select();
        }
    };
    /**
     * Sets the selection start of the text field to a specified value
     */
    TextFieldBase.prototype.setSelectionStart = function (value) {
        if (this._textElement.current) {
            this._textElement.current.selectionStart = value;
        }
    };
    /**
     * Sets the selection end of the text field to a specified value
     */
    TextFieldBase.prototype.setSelectionEnd = function (value) {
        if (this._textElement.current) {
            this._textElement.current.selectionEnd = value;
        }
    };
    Object.defineProperty(TextFieldBase.prototype, "selectionStart", {
        /**
         * Gets the selection start of the text field
         */
        get: function () {
            return this._textElement.current ? this._textElement.current.selectionStart : -1;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(TextFieldBase.prototype, "selectionEnd", {
        /**
         * Gets the selection end of the text field
         */
        get: function () {
            return this._textElement.current ? this._textElement.current.selectionEnd : -1;
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Sets the start and end positions of a selection in a text field.
     * @param start - Index of the start of the selection.
     * @param end - Index of the end of the selection.
     */
    TextFieldBase.prototype.setSelectionRange = function (start, end) {
        if (this._textElement.current) {
            this._textElement.current.setSelectionRange(start, end);
        }
    };
    TextFieldBase.prototype._setValue = function (value) {
        var _this = this;
        this._latestValue = value;
        this.setState({
            value: value || DEFAULT_STATE_VALUE,
            errorMessage: ''
        }, function () {
            _this._adjustInputHeight();
        });
    };
    TextFieldBase.prototype._onFocus = function (ev) {
        if (this.props.onFocus) {
            this.props.onFocus(ev);
        }
        this.setState({ isFocused: true });
        if (this.props.validateOnFocusIn) {
            this._validate(this.state.value);
        }
    };
    TextFieldBase.prototype._onBlur = function (ev) {
        if (this.props.onBlur) {
            this.props.onBlur(ev);
        }
        this.setState({ isFocused: false });
        if (this.props.validateOnFocusOut) {
            this._validate(this.state.value);
        }
    };
    // @deprecated
    TextFieldBase.prototype._onRenderAddon = function (props) {
        var addonString = props.addonString;
        return React.createElement("span", { style: { paddingBottom: '1px' } }, addonString);
    };
    TextFieldBase.prototype._onRenderPrefix = function (props) {
        var prefix = props.prefix;
        return React.createElement("span", { style: { paddingBottom: '1px' } }, prefix);
    };
    TextFieldBase.prototype._onRenderSuffix = function (props) {
        var suffix = props.suffix;
        return React.createElement("span", { style: { paddingBottom: '1px' } }, suffix);
    };
    Object.defineProperty(TextFieldBase.prototype, "_errorMessage", {
        get: function () {
            var errorMessage = this.state.errorMessage;
            if (!errorMessage && this.props.errorMessage) {
                errorMessage = this.props.errorMessage;
            }
            return errorMessage;
        },
        enumerable: true,
        configurable: true
    });
    TextFieldBase.prototype._renderTextArea = function () {
        var textAreaProps = Utilities_1.getNativeProps(this.props, Utilities_1.textAreaProperties, ['defaultValue']);
        return (React.createElement("textarea", tslib_1.__assign({ id: this._id }, textAreaProps, { ref: this._textElement, value: this.state.value, onInput: this._onInputChange, onChange: this._onInputChange, className: this._classNames.field, "aria-describedby": this._isDescriptionAvailable ? this._descriptionId : this.props['aria-describedby'], "aria-invalid": !!this.state.errorMessage, "aria-label": this.props.ariaLabel, readOnly: this.props.readOnly, onFocus: this._onFocus, onBlur: this._onBlur })));
    };
    TextFieldBase.prototype._renderInput = function () {
        var inputProps = Utilities_1.getNativeProps(this.props, Utilities_1.inputProperties, ['defaultValue']);
        return (React.createElement("input", tslib_1.__assign({ type: 'text', id: this._id }, inputProps, { ref: this._textElement, value: this.state.value, onInput: this._onInputChange, onChange: this._onInputChange, className: this._classNames.field, "aria-label": this.props.ariaLabel, "aria-describedby": this._isDescriptionAvailable ? this._descriptionId : this.props['aria-describedby'], "aria-invalid": !!this.state.errorMessage, readOnly: this.props.readOnly, onFocus: this._onFocus, onBlur: this._onBlur })));
    };
    TextFieldBase.prototype._onInputChange = function (event) {
        var _this = this;
        event.persist();
        var element = event.target;
        var value = element.value;
        // Avoid doing unnecessary work when the value has not changed.
        if (value === this._latestValue) {
            return;
        }
        this._latestValue = value;
        this.setState({
            value: value
        }, function () {
            _this._adjustInputHeight();
            if (_this.props.onChange) {
                _this.props.onChange(event, value);
            }
            if (_this.props.onChanged) {
                _this.props.onChanged(value);
            }
        });
        var _a = this.props, validateOnFocusIn = _a.validateOnFocusIn, validateOnFocusOut = _a.validateOnFocusOut;
        if (!(validateOnFocusIn || validateOnFocusOut)) {
            this._delayedValidate(value);
        }
        var onBeforeChange = this.props.onBeforeChange;
        onBeforeChange(value);
    };
    TextFieldBase.prototype._validate = function (value) {
        var _this = this;
        var _a = this.props, validateOnFocusIn = _a.validateOnFocusIn, validateOnFocusOut = _a.validateOnFocusOut;
        // In case of _validate called multi-times during executing validate logic with promise return.
        if (this._latestValidateValue === value && !(validateOnFocusIn || validateOnFocusOut)) {
            return;
        }
        this._latestValidateValue = value;
        var onGetErrorMessage = this.props.onGetErrorMessage;
        var result = onGetErrorMessage(value || '');
        if (result !== undefined) {
            if (typeof result === 'string') {
                this.setState({
                    errorMessage: result
                });
                this._notifyAfterValidate(value, result);
            }
            else {
                var currentValidation_1 = ++this._lastValidation;
                result.then(function (errorMessage) {
                    if (_this._isMounted && currentValidation_1 === _this._lastValidation) {
                        _this.setState({ errorMessage: errorMessage });
                    }
                    _this._notifyAfterValidate(value, errorMessage);
                });
            }
        }
        else {
            this._notifyAfterValidate(value, '');
        }
    };
    TextFieldBase.prototype._notifyAfterValidate = function (value, errorMessage) {
        if (this._isMounted && value === this.state.value && this.props.onNotifyValidationResult) {
            this.props.onNotifyValidationResult(errorMessage, value);
        }
    };
    TextFieldBase.prototype._adjustInputHeight = function () {
        if (this._textElement.current && this.props.autoAdjustHeight && this.props.multiline) {
            var textField = this._textElement.current;
            textField.style.height = '';
            var scrollHeight = textField.scrollHeight + 2; // +2 to avoid vertical scroll bars
            textField.style.height = scrollHeight + 'px';
        }
    };
    TextFieldBase.defaultProps = {
        multiline: false,
        resizable: true,
        autoAdjustHeight: false,
        underlined: false,
        borderless: false,
        onChange: function () {
            /* noop */
        },
        onBeforeChange: function () {
            /* noop */
        },
        onNotifyValidationResult: function () {
            /* noop */
        },
        onGetErrorMessage: function () { return undefined; },
        deferredValidationTime: 200,
        errorMessage: '',
        validateOnFocusIn: false,
        validateOnFocusOut: false,
        validateOnLoad: true
    };
    return TextFieldBase;
}(Utilities_1.BaseComponent));
exports.TextFieldBase = TextFieldBase;
//# sourceMappingURL=TextField.base.js.map