text: "use strict";
  /*
   * Copyright 2016 Palantir Technologies, Inc. All rights reserved.
   *
   * Licensed under the terms of the LICENSE file distributed with this project.
   */
  Object.defineProperty(exports, "__esModule", { value: true });
  var tslib_1 = require("tslib");
  var classnames_1 = tslib_1.__importDefault(require("classnames"));
  var React = tslib_1.__importStar(require("react"));
  var abstractPureComponent_1 = require("../../common/abstractPureComponent");
  var Classes = tslib_1.__importStar(require("../../common/classes"));
  var Keys = tslib_1.__importStar(require("../../common/keys"));
  var props_1 = require("../../common/props");
  var utils_1 = require("../../common/utils");
  var sliderUtils_1 = require("./sliderUtils");
  // props that require number values, for validation
  var NUMBER_PROPS = ["max", "min", "stepSize", "tickSize", "value"];
  /** Internal component for a Handle with click/drag/keyboard logic to determine a new value. */
  var Handle = /** @class */ (function (_super) {
      tslib_1.__extends(Handle, _super);
      function Handle() {
          var _this = _super !== null && _super.apply(this, arguments) || this;
          _this.state = {
              isMoving: false,
          };
          _this.refHandlers = {
              handle: function (el) { return (_this.handleElement = el); },
          };
          _this.beginHandleMovement = function (event) {
              document.addEventListener("mousemove", _this.handleHandleMovement);
              document.addEventListener("mouseup", _this.endHandleMovement);
              _this.setState({ isMoving: true });
              _this.changeValue(_this.clientToValue(_this.mouseEventClientOffset(event)));
          };
          _this.beginHandleTouchMovement = function (event) {
              document.addEventListener("touchmove", _this.handleHandleTouchMovement);
              document.addEventListener("touchend", _this.endHandleTouchMovement);
              document.addEventListener("touchcancel", _this.endHandleTouchMovement);
              _this.setState({ isMoving: true });
              _this.changeValue(_this.clientToValue(_this.touchEventClientOffset(event)));
          };
          _this.endHandleMovement = function (event) {
              _this.handleMoveEndedAt(_this.mouseEventClientOffset(event));
          };
          _this.endHandleTouchMovement = function (event) {
              _this.handleMoveEndedAt(_this.touchEventClientOffset(event));
          };
          _this.handleMoveEndedAt = function (clientPixel) {
              _this.removeDocumentEventListeners();
              _this.setState({ isMoving: false });
              // always invoke onRelease; changeValue may call onChange if value is different
              var onRelease = _this.props.onRelease;
              var finalValue = _this.changeValue(_this.clientToValue(clientPixel));
              utils_1.safeInvoke(onRelease, finalValue);
          };
          _this.handleHandleMovement = function (event) {
              _this.handleMovedTo(_this.mouseEventClientOffset(event));
          };
          _this.handleHandleTouchMovement = function (event) {
              _this.handleMovedTo(_this.touchEventClientOffset(event));
          };
          _this.handleMovedTo = function (clientPixel) {
              if (_this.state.isMoving && !_this.props.disabled) {
                  _this.changeValue(_this.clientToValue(clientPixel));
              }
          };
          _this.handleKeyDown = function (event) {
              var _a = _this.props, stepSize = _a.stepSize, value = _a.value;
              var which = event.which;
              if (which === Keys.ARROW_DOWN || which === Keys.ARROW_LEFT) {
                  _this.changeValue(value - stepSize);
                  // this key event has been handled! prevent browser scroll on up/down
                  event.preventDefault();
              }
              else if (which === Keys.ARROW_UP || which === Keys.ARROW_RIGHT) {
                  _this.changeValue(value + stepSize);
                  event.preventDefault();
              }
          };
          _this.handleKeyUp = function (event) {
              if ([Keys.ARROW_UP, Keys.ARROW_DOWN, Keys.ARROW_LEFT, Keys.ARROW_RIGHT].indexOf(event.which) >= 0) {
                  utils_1.safeInvoke(_this.props.onRelease, _this.props.value);
              }
          };
          return _this;
      }
      Handle.prototype.componentDidMount = function () {
          // The first time this component renders, it has no ref to the handle and thus incorrectly centers the handle.
          // Therefore, on the first mount, force a re-render to center the handle with the ref'd component.
          this.forceUpdate();
      };
      Handle.prototype.render = function () {
          var _a = this.props, className = _a.className, disabled = _a.disabled, label = _a.label, min = _a.min, tickSizeRatio = _a.tickSizeRatio, value = _a.value, vertical = _a.vertical;
          var isMoving = this.state.isMoving;
          // The handle midpoint of RangeSlider is actually shifted by a margin to
          // be on the edge of the visible handle element. Because the midpoint
          // calculation does not take this margin into account, we instead
          // measure the long side (which is equal to the short side plus the
          // margin).
          var handleMidpoint = this.getHandleMidpointAndOffset(this.handleElement, true).handleMidpoint;
          var offsetRatio = (value - min) * tickSizeRatio;
          var offsetCalc = "calc(" + sliderUtils_1.formatPercentage(offsetRatio) + " - " + handleMidpoint + "px)";
          var style = vertical ? { bottom: offsetCalc } : { left: offsetCalc };
          return (React.createElement("span", { className: classnames_1.default(Classes.SLIDER_HANDLE, (_b = {}, _b[Classes.ACTIVE] = isMoving, _b), className), onKeyDown: disabled ? null : this.handleKeyDown, onKeyUp: disabled ? null : this.handleKeyUp, onMouseDown: disabled ? null : this.beginHandleMovement, onTouchStart: disabled ? null : this.beginHandleTouchMovement, ref: this.refHandlers.handle, style: style, tabIndex: 0 }, label == null ? null : React.createElement("span", { className: Classes.SLIDER_LABEL }, label)));
          var _b;
      };
      Handle.prototype.componentWillUnmount = function () {
          this.removeDocumentEventListeners();
      };
      /** Convert client pixel to value between min and max. */
      Handle.prototype.clientToValue = function (clientPixel) {
          var _a = this.props, stepSize = _a.stepSize, tickSize = _a.tickSize, value = _a.value, vertical = _a.vertical;
          if (this.handleElement == null) {
              return value;
          }
          // #1769: this logic doesn't work perfectly when the tick size is
          // smaller than the handle size; it may be off by a tick or two.
          var clientPixelNormalized = vertical ? window.innerHeight - clientPixel : clientPixel;
          var handleCenterPixel = this.getHandleElementCenterPixel(this.handleElement);
          var pixelDelta = clientPixelNormalized - handleCenterPixel;
          if (isNaN(pixelDelta)) {
              return value;
          }
          // convert pixels to range value in increments of `stepSize`
          return value + Math.round(pixelDelta / (tickSize * stepSize)) * stepSize;
      };
      Handle.prototype.mouseEventClientOffset = function (event) {
          return this.props.vertical ? event.clientY : event.clientX;
      };
      Handle.prototype.touchEventClientOffset = function (event) {
          var touch = event.changedTouches[0];
          return this.props.vertical ? touch.clientY : touch.clientX;
      };
      Handle.prototype.validateProps = function (props) {
          for (var _i = 0, NUMBER_PROPS_1 = NUMBER_PROPS; _i < NUMBER_PROPS_1.length; _i++) {
              var prop = NUMBER_PROPS_1[_i];
              if (typeof props[prop] !== "number") {
                  throw new Error("[Blueprint] <Handle> requires number value for " + prop + " prop");
              }
          }
      };
      /** Clamp value and invoke callback if it differs from current value */
      Handle.prototype.changeValue = function (newValue, callback) {
          if (callback === void 0) { callback = this.props.onChange; }
          newValue = this.clamp(newValue);
          if (!isNaN(newValue) && this.props.value !== newValue) {
              utils_1.safeInvoke(callback, newValue);
          }
          return newValue;
      };
      /** Clamp value between min and max props */
      Handle.prototype.clamp = function (value) {
          return utils_1.clamp(value, this.props.min, this.props.max);
      };
      Handle.prototype.getHandleElementCenterPixel = function (handleElement) {
          var _a = this.getHandleMidpointAndOffset(handleElement), handleMidpoint = _a.handleMidpoint, handleOffset = _a.handleOffset;
          return handleOffset + handleMidpoint;
      };
      Handle.prototype.getHandleMidpointAndOffset = function (handleElement, useOppositeDimension) {
          if (useOppositeDimension === void 0) { useOppositeDimension = false; }
          if (handleElement == null) {
              return { handleMidpoint: 0, handleOffset: 0 };
          }
          var vertical = this.props.vertical;
          // getBoundingClientRect().height includes border size; clientHeight does not.
          var handleRect = handleElement.getBoundingClientRect();
          var sizeKey = vertical
              ? useOppositeDimension ? "width" : "height"
              : useOppositeDimension ? "height" : "width";
          // "bottom" value seems to be consistently incorrect, so explicitly
          // calculate it using the window offset instead.
          var handleOffset = vertical ? window.innerHeight - (handleRect.top + handleRect[sizeKey]) : handleRect.left;
          return { handleMidpoint: handleRect[sizeKey] / 2, handleOffset: handleOffset };
      };
      Handle.prototype.removeDocumentEventListeners = function () {
          document.removeEventListener("mousemove", this.handleHandleMovement);
          document.removeEventListener("mouseup", this.endHandleMovement);
          document.removeEventListener("touchmove", this.handleHandleTouchMovement);
          document.removeEventListener("touchend", this.endHandleTouchMovement);
          document.removeEventListener("touchcancel", this.endHandleTouchMovement);
      };
      Handle.displayName = props_1.DISPLAYNAME_PREFIX + ".SliderHandle";
      return Handle;
  }(abstractPureComponent_1.AbstractPureComponent));
  exports.Handle = Handle;
  //# sourceMappingURL=handle.js.map