azure-devops-ui
Version:
React components for building web UI in Azure DevOps
146 lines (145 loc) • 7.91 kB
JavaScript
import { __extends } from "tslib";
import "../../CommonImports";
import "../../Core/core.css";
import "./Sizer.css";
import * as React from "react";
import { ObservableLike } from '../../Core/Observable';
import { TimerManagement } from '../../Core/TimerManagement';
import { Observer } from '../../Observer';
import { Portal } from '../../Portal';
import { css, KeyCode, Mouse } from '../../Util';
import { Orientation, Position } from "./Sizer.Props";
import { Tooltip } from '../../TooltipEx';
import * as Resources from '../../Resources.Widgets';
var Sizer = /** @class */ (function (_super) {
__extends(Sizer, _super);
function Sizer(props) {
var _this = _super.call(this, props) || this;
_this.lastLocation = -1;
_this.timerManagement = new TimerManagement();
_this.state = { showPortal: false };
_this.onDragStart = function (event) {
// Prevent default to stop the ColumnDragDropBehavior from trying to handle this event.
event.preventDefault();
};
_this.onMouseCapture = function (event) {
// Recompute the size and update the lastLocation based on the amount changed.
_this.lastLocation += _this.updateSize(event, _this.getMouseLocation(event) - _this.lastLocation);
// Remove the portal now that we are no longer sizing.
if (event.type === "mouseup") {
_this.setState({ showPortal: false });
// If the user wanted to know when the sizing was complete, we will notify
// the now that sizing is complete.
_this.onSizeEnd();
}
};
_this.onKeyDown = function (event) {
var _a;
if (!event.defaultPrevented) {
var orientation_1 = _this.props.orientation;
var sizeChange = void 0;
if (orientation_1 === Orientation.row) {
if (event.which === KeyCode.enter) {
var focuselt = _this.props.getFocusedElement(event);
(_a = focuselt === null || focuselt === void 0 ? void 0 : focuselt.current) === null || _a === void 0 ? void 0 : _a.focus();
}
if (event.which === KeyCode.leftArrow) {
sizeChange = _this.updateSize(event.nativeEvent, -1, true);
}
else if (event.which === KeyCode.rightArrow) {
sizeChange = _this.updateSize(event.nativeEvent, 1, true);
}
}
else {
if (event.which === KeyCode.upArrow) {
sizeChange = _this.updateSize(event.nativeEvent, -1, true);
}
else if (event.which === KeyCode.downArrow) {
sizeChange = _this.updateSize(event.nativeEvent, 1, true);
}
}
// If we changed the size, we will prevent the default and start a
// timer to end the sizing operation. Since there is no gesture to
// start and complete with the keyboard.
if (sizeChange) {
event.preventDefault();
_this.debouncedEnd();
}
}
};
_this.onSizeEnd = function () {
if (_this.props.onSizeEnd) {
_this.props.onSizeEnd(_this.props.id);
}
};
_this.onMouseDown = function (event) {
// Look for only main button clicks, not right click
if (!event.defaultPrevented && event.button === 0) {
_this.lastLocation = _this.getMouseLocation(event.nativeEvent);
// Capture the mouse, this will let us size the column even when the mouse moves
// outside our element.
Mouse.setCapture(_this.onMouseCapture);
// Show the portal that keeps our sizing actions for effecting the other elements.
_this.setState({ showPortal: true });
// Don't let the event set focus or start a mouse selection.
event.preventDefault();
}
};
_this.debouncedEnd = _this.timerManagement.debounce(_this.onSizeEnd, 500, { trailing: true });
return _this;
}
Sizer.prototype.render = function () {
var divider = this.props.divider;
return (React.createElement(Tooltip, { text: Resources.SizerAnnouncement },
React.createElement("div", { "aria-label": this.props.ariaLabel || Resources.SizerAnnouncement, "aria-valuetext": "".concat(ObservableLike.getValue(this.props.size), " pixels wide"), "aria-valuenow": ObservableLike.getValue(this.props.size), className: css(this.props.className, "bolt-sizer", this.props.orientation === Orientation.row ? "bolt-sizer-row flex-row" : "bolt-sizer-column flex-column", divider && "divider"), id: this.props.id, onKeyDown: this.onKeyDown, onMouseDown: this.onMouseDown, onDragStart: this.onDragStart, role: "separator", tabIndex: this.props.tabIndex }, this.state.showPortal && (React.createElement(Portal, { className: css("bolt-sizer-portal", this.props.orientation === Orientation.row ? "bolt-sizer-portal-row" : "bolt-sizer-portal-column") },
React.createElement("div", null))))));
};
Sizer.prototype.componentWillUnmount = function () {
Mouse.releaseCapture(this.onMouseCapture);
this.timerManagement.dispose();
};
Sizer.prototype.getMouseLocation = function (event) {
return this.props.orientation === Orientation.row ? event.pageX : event.pageY;
};
Sizer.prototype.updateSize = function (event, sizeChange, applyKeyboardMultiplier) {
if (applyKeyboardMultiplier === void 0) { applyKeyboardMultiplier = false; }
// Compute the udpated size of the Sized element.
var currentSize = ObservableLike.getValue(this.props.size);
var multiplier = this.props.position === Position.far ? -1 : 1;
var keyboardStepMultiplier = applyKeyboardMultiplier ? this.props.keyboardStepMultiplier || 1 : 1;
var updatedSize = Math.floor(Math.min(this.props.maxSize, Math.max(this.props.minSize, currentSize + sizeChange * multiplier * keyboardStepMultiplier)));
// Notify the caller of the updated size.
this.props.onSize(event, updatedSize, this.props.id);
// console.log("currentSize = " + currentSize + " updateSize = " + updatedSize);
return (updatedSize - currentSize) * multiplier;
};
Sizer.defaultProps = {
divider: true,
maxSize: 10000,
minSize: 100
};
return Sizer;
}(React.Component));
export { Sizer };
/**
* The Sized function is used to produce a div that has a fixed width or height
* based on the orientation of the sized props. This is a basic component that
* can be used with the Sizer to produce a basic splitter like UI.
*
* @param props properties to render the appropriate container element given the
* props.
*/
export function Sized(props) {
return (React.createElement(Observer, { height: props.height, width: props.width }, function (observedProps) {
var style = {};
// Add any specific height that has been defined.
if (observedProps.height !== undefined) {
style.height = observedProps.height + "px";
}
// Add any specific width that has been defined.
if (observedProps.width !== undefined) {
style.width = observedProps.width + "px";
}
return (React.createElement("div", { className: css(props.className, "flex-noshrink"), style: style }, props.children));
}));
}