define(["require", "exports", "tslib", "react", "../../Utilities", "../../TextField", "./ColorRectangle/ColorRectangle", "./ColorSlider/ColorSlider", "../../utilities/color/consts", "../../utilities/color/getColorFromString", "../../utilities/color/getColorFromRGBA", "../../utilities/color/updateA", "../../utilities/color/updateH", "../../utilities/color/correctRGB", "../../utilities/color/correctHex", "./ColorRectangle/ColorRectangle.base"], function (require, exports, tslib_1, React, Utilities_1, TextField_1, ColorRectangle_1, ColorSlider_1, consts_1, getColorFromString_1, getColorFromRGBA_1, updateA_1, updateH_1, correctRGB_1, correctHex_1, ColorRectangle_base_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var getClassNames = Utilities_1.classNamesFunction();
    var colorComponents = ['hex', 'r', 'g', 'b', 'a'];
    /**
     * {@docCategory ColorPicker}
     */
    var ColorPickerBase = /** @class */ (function (_super) {
        tslib_1.__extends(ColorPickerBase, _super);
        function ColorPickerBase(props) {
            var _this = _super.call(this, props) || this;
            _this._onSVChanged = function (ev, color) {
                _this._updateColor(ev, color);
            };
            _this._onHChanged = function (ev, h) {
                _this._updateColor(ev, updateH_1.updateH(_this.state.color, h));
            };
            _this._onAChanged = function (ev, a) {
                _this._updateColor(ev, updateA_1.updateA(_this.state.color, Math.round(a)));
            };
            _this._onBlur = function (event) {
                var _a;
                var _b = _this.state, color = _b.color, editingColor = _b.editingColor;
                if (!editingColor) {
                    return;
                }
                // If there was an intermediate incorrect value (such as too large or empty), correct it.
                var value = editingColor.value, component = editingColor.component;
                var isHex = component === 'hex';
                var minLength = isHex ? consts_1.MIN_HEX_LENGTH : consts_1.MIN_RGBA_LENGTH;
                if (value.length >= minLength && (isHex || !isNaN(Number(value)))) {
                    // Real value. Clamp to appropriate length (hex) or range (rgba).
                    var newColor = void 0;
                    if (isHex) {
                        newColor = getColorFromString_1.getColorFromString('#' + correctHex_1.correctHex(value));
                    }
                    else {
                        newColor = getColorFromRGBA_1.getColorFromRGBA(correctRGB_1.correctRGB(tslib_1.__assign({}, color, (_a = {}, _a[component] = Number(value), _a))));
                    }
                    // Update state and call onChange
                    _this._updateColor(event, newColor);
                }
                else {
                    // Intermediate value was an empty string, too short (hex only), or just . (alpha only).
                    // Just clear the intermediate state and revert to the previous value.
                    _this.setState({ editingColor: undefined });
                }
            };
            Utilities_1.initializeComponentRef(_this);
            _this.state = {
                color: _getColorFromProps(props) || getColorFromString_1.getColorFromString('#ffffff')
            };
            _this._textChangeHandlers = {};
            for (var _i = 0, colorComponents_1 = colorComponents; _i < colorComponents_1.length; _i++) {
                var component = colorComponents_1[_i];
                _this._textChangeHandlers[component] = _this._onTextChange.bind(_this, component);
            }
            var strings = props.strings; // always defined since it's in defaultProps
            var defaultStrings = ColorPickerBase.defaultProps.strings;
            _this._textLabels = {
                r: props.redLabel || strings.red || defaultStrings.red,
                g: props.greenLabel || strings.green || defaultStrings.green,
                b: props.blueLabel || strings.blue || defaultStrings.blue,
                a: props.alphaLabel || strings.alpha || defaultStrings.alpha,
                hex: props.hexLabel || strings.hex || defaultStrings.hex
            };
            _this._strings = tslib_1.__assign({}, defaultStrings, strings);
            return _this;
        }
        Object.defineProperty(ColorPickerBase.prototype, "color", {
            get: function () {
                return this.state.color;
            },
            enumerable: true,
            configurable: true
        });
        ColorPickerBase.prototype.componentDidUpdate = function (prevProps, prevState) {
            // if props changed (as opposed to a state update), update the color
            if (prevProps !== this.props) {
                var color = _getColorFromProps(this.props);
                if (color) {
                    this._updateColor(undefined, color);
                }
            }
        };
        ColorPickerBase.prototype.render = function () {
            var _this = this;
            var props = this.props;
            var strings = this._strings;
            var textLabels = this._textLabels;
            var theme = props.theme, className = props.className, styles = props.styles, alphaSliderHidden = props.alphaSliderHidden;
            var color = this.state.color;
            var classNames = getClassNames(styles, {
                theme: theme,
                className: className
            });
            var colorStr = color.str || '';
            // Space out hex and RGBA colors for more helpful reading
            var selectedColorAria = colorStr[0] === '#'
                ? colorStr.split('').join(' ')
                : colorStr.indexOf('rgba(') === 0
                    ? "R G B A " + color.r + " " + color.g + " " + color.b + " " + color.a + "%"
                    : colorStr;
            var ariaLabel = strings.rootAriaLabelFormat.replace('{0}', selectedColorAria);
            return (React.createElement("div", { className: classNames.root, role: "group", "aria-label": ariaLabel },
                React.createElement("div", { className: classNames.panel },
                    React.createElement(ColorRectangle_1.ColorRectangle, { color: color, onChange: this._onSVChanged, ariaLabel: strings.svAriaLabel, ariaDescription: strings.svAriaDescription, ariaValueFormat: strings.svAriaValueFormat, className: classNames.colorRectangle }),
                    React.createElement("div", { className: classNames.flexContainer },
                        React.createElement("div", { className: classNames.flexSlider },
                            React.createElement(ColorSlider_1.ColorSlider, { className: "is-hue", ariaLabel: strings.hue || strings.hueAriaLabel, minValue: 0, maxValue: consts_1.MAX_COLOR_HUE, value: color.h, onChange: this._onHChanged }),
                            !alphaSliderHidden && (React.createElement(ColorSlider_1.ColorSlider, { className: "is-alpha", isAlpha: true, ariaLabel: strings.alphaAriaLabel || textLabels.a, overlayColor: color.hex, minValue: 0, maxValue: consts_1.MAX_COLOR_ALPHA, value: color.a, onChange: this._onAChanged }))),
                        props.showPreview && (React.createElement("div", { className: classNames.flexPreviewBox },
                            React.createElement("div", { className: classNames.colorSquare + ' is-preview', style: {
                                    backgroundColor: color.str
                                } })))),
                    React.createElement("table", { className: classNames.table, role: "group", cellPadding: "0", cellSpacing: "0" },
                        React.createElement("thead", null,
                            React.createElement("tr", { className: classNames.tableHeader },
                                React.createElement("td", { className: classNames.tableHexCell }, textLabels.hex),
                                React.createElement("td", null, textLabels.r),
                                React.createElement("td", null, textLabels.g),
                                React.createElement("td", null, textLabels.b),
                                !alphaSliderHidden && React.createElement("td", null, textLabels.a))),
                        React.createElement("tbody", null,
                            React.createElement("tr", null, colorComponents.map(function (comp) {
                                if (comp === 'a' && alphaSliderHidden) {
                                    return null;
                                }
                                return (React.createElement("td", { key: comp, style: comp === 'hex' ? undefined : { width: '18%' } },
                                    React.createElement(TextField_1.TextField, { className: classNames.input, onChange: _this._textChangeHandlers[comp], onBlur: _this._onBlur, value: _this._getDisplayValue(comp), spellCheck: false, ariaLabel: textLabels[comp], autoComplete: "off" })));
                            })))))));
        };
        ColorPickerBase.prototype._getDisplayValue = function (component) {
            var _a = this.state, color = _a.color, editingColor = _a.editingColor;
            if (editingColor && editingColor.component === component) {
                return editingColor.value;
            }
            if (component === 'hex') {
                return color[component] || '';
            }
            else if (typeof color[component] === 'number' && !isNaN(color[component])) {
                return String(color[component]);
            }
            return '';
        };
        ColorPickerBase.prototype._onTextChange = function (component, event, newValue) {
            var _a;
            var color = this.state.color;
            var isHex = component === 'hex';
            var isAlpha = component === 'a';
            newValue = (newValue || '').substr(0, isHex ? consts_1.MAX_HEX_LENGTH : consts_1.MAX_RGBA_LENGTH);
            // Ignore what the user typed if it contains invalid characters
            var validCharsRegex = isHex ? consts_1.HEX_REGEX : consts_1.RGBA_REGEX;
            if (!validCharsRegex.test(newValue)) {
                return;
            }
            // Determine if the entry is valid (different methods for hex, alpha, and RGB)
            var isValid;
            if (newValue === '') {
                // Empty string is obviously not valid
                isValid = false;
            }
            else if (isHex) {
                // Technically hex values of length 3 are also valid, but committing the value here would
                // cause it to be automatically converted to a value of length 6, which may not be what the
                // user wanted if they're not finished typing. (Values of length 3 will be committed on blur.)
                isValid = newValue.length === consts_1.MAX_HEX_LENGTH;
            }
            else if (isAlpha) {
                isValid = Number(newValue) <= consts_1.MAX_COLOR_ALPHA;
            }
            else {
                isValid = Number(newValue) <= consts_1.MAX_COLOR_RGB;
            }
            if (!isValid) {
                // If the new value is an empty string or other invalid value, save that to display.
                // (if the user still hasn't entered anything on blur, the last value is restored)
                this.setState({ editingColor: { component: component, value: newValue } });
            }
            else if (String(color[component]) === newValue) {
                // If the new value is the same as the current value, mostly ignore it.
                // Exception is that if the user was previously editing the value (but hadn't yet entered
                // a new valid value), we should clear the intermediate value.
                if (this.state.editingColor) {
                    this.setState({ editingColor: undefined });
                }
            }
            else {
                // Should be a valid color. Update the value.
                var newColor = isHex
                    ? getColorFromString_1.getColorFromString('#' + newValue)
                    : getColorFromRGBA_1.getColorFromRGBA(tslib_1.__assign({}, color, (_a = {}, _a[component] = Number(newValue), _a)));
                this._updateColor(event, newColor);
            }
        };
        /**
         * Update the displayed color and call change handlers if appropriate.
         * @param ev - Event if call was triggered by an event (undefined if triggered by props change)
         * @param newColor - Updated color
         */
        ColorPickerBase.prototype._updateColor = function (ev, newColor) {
            if (!newColor) {
                return;
            }
            var _a = this.state, color = _a.color, editingColor = _a.editingColor;
            var isDifferentColor = newColor.h !== color.h || newColor.str !== color.str;
            if (isDifferentColor || editingColor) {
                // If ev is undefined, it's an update from props (which should be unconditionally respected
                // and not call onChange).
                if (ev && this.props.onChange) {
                    this.props.onChange(ev, newColor);
                    if (ev.defaultPrevented) {
                        return;
                    }
                }
                this.setState({ color: newColor, editingColor: undefined });
            }
        };
        ColorPickerBase.defaultProps = {
            strings: {
                rootAriaLabelFormat: 'Color picker, {0} selected.',
                hex: 'Hex',
                red: 'Red',
                green: 'Green',
                blue: 'Blue',
                alpha: 'Alpha',
                hueAriaLabel: 'Hue',
                svAriaLabel: ColorRectangle_base_1.ColorRectangleBase.defaultProps.ariaLabel,
                svAriaValueFormat: ColorRectangle_base_1.ColorRectangleBase.defaultProps.ariaValueFormat,
                svAriaDescription: ColorRectangle_base_1.ColorRectangleBase.defaultProps.ariaDescription
            }
        };
        return ColorPickerBase;
    }(React.Component));
    exports.ColorPickerBase = ColorPickerBase;
    function _getColorFromProps(props) {
        var color = props.color;
        return typeof color === 'string' ? getColorFromString_1.getColorFromString(color) : color;
    }
});
//# sourceMappingURL=ColorPicker.base.js.map