azure-devops-ui
Version:
React components for building web UI in Azure DevOps
132 lines (131 loc) • 8.29 kB
JavaScript
import "../../CommonImports";
import "../../Core/core.css";
import "./Dialog.css";
import * as React from "react";
import { EventManagement } from '../../Core/EventManagement';
import { announce } from '../../Core/Util/Accessibility';
import { ScreenContext, ScreenSize } from '../../Core/Util/Screen';
import { format } from '../../Core/Util/String';
import { Callout, ContentJustification, ContentLocation, ContentOrientation, ContentSize } from '../../Callout';
import { FocusZoneKeyStroke } from '../../FocusZone';
import { Icon } from '../../Icon';
import { Observer } from '../../Observer';
import * as Resources from '../../Resources.Layer';
import { Spinner, SpinnerSize } from '../../Spinner';
import { Spacing, Surface, SurfaceContext } from '../../Surface';
import { css, KeyCode } from '../../Util';
const MIN_DIALOG_Size = 320;
const DIALOG_RESIZE_INCREMENT = 2;
export class CustomDialog extends React.Component {
constructor(props) {
super(props);
this.events = new EventManagement();
this.contentRef = React.createRef();
this.onGripperKeyDown = (event) => {
if (this.contentRef.current) {
const rect = this.contentRef.current.getBoundingClientRect();
this.currentHeight = rect.height;
this.currentWidth = rect.width;
switch (event.keyCode) {
case KeyCode.leftArrow:
this.setState({ width: Math.max(this.currentWidth - DIALOG_RESIZE_INCREMENT, MIN_DIALOG_Size) });
break;
case KeyCode.rightArrow:
this.setState({ width: this.currentWidth + DIALOG_RESIZE_INCREMENT });
break;
case KeyCode.upArrow:
this.setState({ height: Math.max(this.currentHeight - DIALOG_RESIZE_INCREMENT, MIN_DIALOG_Size) });
break;
case KeyCode.downArrow:
this.setState({ height: this.currentHeight + DIALOG_RESIZE_INCREMENT });
break;
default:
return;
}
event.preventDefault();
event.stopPropagation();
announce(format(Resources.SizeFormat, this.state.height || this.currentHeight, this.state.width || this.currentWidth));
}
};
this.onGripperMouseDown = (event) => {
this.onGripperDown(event, event.clientX, event.clientY);
this.attachMouseWindowEvents();
};
this.onGripperDown = (event, xPos, yPos) => {
if (this.contentRef) {
event.preventDefault();
event.stopPropagation();
this.anchorX = xPos;
this.anchorY = yPos;
if (this.contentRef.current) {
const rect = this.contentRef.current.getBoundingClientRect();
this.currentHeight = rect.height;
this.currentWidth = rect.width;
}
}
};
this.onGripperMouseMove = (event) => {
this.handleDragEvent(event, event.clientX, event.clientY);
};
this.onGripperMouseUp = (event) => {
this.detachMouseWindowEvents();
announce(format(Resources.SizeFormat, this.state.height, this.state.width));
};
this.onKeyDown = (event) => {
var _a;
const { enterPrimary, primaryButtonProps } = this.props;
if (enterPrimary && primaryButtonProps && event.which === KeyCode.enter && !event.defaultPrevented) {
(_a = primaryButtonProps.onClick) === null || _a === void 0 ? void 0 : _a.call(primaryButtonProps, event);
event.preventDefault();
}
};
this.state = {};
}
render() {
const { ariaDescribedBy, ariaLabel, ariaLabelledBy, blurDismiss, calloutClassName, className, calloutContentClassName, contentJustification, contentLocation, defaultActiveElement, defaultFocusableElementAriaLabel, escDismiss, id, lightDismiss, onDismiss, overlay, modal, resizable, role, contentSize = ContentSize.Medium } = this.props;
return (React.createElement(Observer, { size: this.context.size }, (props) => {
const mobile = props.size === ScreenSize.xsmall;
return (React.createElement(Callout, { ariaDescribedBy: ariaDescribedBy, ariaLabel: ariaLabel, ariaLabelledBy: ariaLabelledBy, blurDismiss: blurDismiss, className: css(calloutClassName, "bolt-dialog-callout"), contentClassName: css(calloutContentClassName, "bolt-dialog-callout-content relative scroll-auto", mobile && "bolt-dialog-mobile flex-grow"), contentJustification: contentJustification, contentLocation: contentLocation, contentOrientation: ContentOrientation.Column, contentRef: this.contentRef, contentShadow: true, contentSize: mobile ? undefined : contentSize, escDismiss: escDismiss, focuszoneProps: {
circularNavigation: true,
defaultActiveElement: defaultActiveElement || ".bolt-dialog-focus-element",
focusOnMount: true,
handleTabKey: true,
includeDefaults: true,
selectInputTextOnFocus: this.props.selectInputTextOnFocus,
postprocessKeyStroke: function (event) {
// We want to prevent moving outside the dialog if there are no focusable elements in the dialog.
event.which === KeyCode.tab && event.preventDefault();
return FocusZoneKeyStroke.IgnoreParents;
}
}, id: id, lightDismiss: lightDismiss, modal: modal, onDismiss: onDismiss, role: role, height: this.state.height, width: this.state.width, onKeyDown: this.onKeyDown },
React.createElement(SurfaceContext.Consumer, null, surfaceContext => (React.createElement(Surface, Object.assign({}, surfaceContext, { spacing: Spacing.default }),
React.createElement("div", { className: css(className, "bolt-dialog-root flex-column flex-grow scroll-hidden") },
React.createElement("div", { "aria-label": defaultFocusableElementAriaLabel, className: "bolt-dialog-focus-element no-outline", tabIndex: -1, role: defaultFocusableElementAriaLabel ? "heading" : undefined, "aria-level": defaultFocusableElementAriaLabel ? 1 : undefined }),
this.props.children,
!mobile && resizable && (React.createElement(Icon, { ariaLabel: Resources.Resize, iconName: "GripperResize", onMouseDown: this.onGripperMouseDown, onKeyDown: this.onGripperKeyDown, tabIndex: 0, wrapperClass: "bolt-dialog-resize-icon" })),
overlay && (React.createElement("div", { className: "absolute-fill bolt-dialog-overlay flex-column justify-center" },
React.createElement(Spinner, { size: SpinnerSize.large, ariaLabel: overlay.spinnerAriaLabel, ariaLive: "assertive", label: overlay.spinnerLabel })))))))));
}));
}
handleDragEvent(event, xPos, yPos) {
const newWidth = Math.max((this.currentWidth || 0) + (xPos - this.anchorX) * 2, MIN_DIALOG_Size);
const newHeight = Math.max((this.currentHeight || 0) + (yPos - this.anchorY) * 2, MIN_DIALOG_Size);
this.setState({ width: newWidth, height: newHeight });
}
attachMouseWindowEvents() {
this.events.addEventListener(window, "mousemove", this.onGripperMouseMove);
this.events.addEventListener(window, "mouseup", this.onGripperMouseUp);
}
detachMouseWindowEvents() {
this.events.removeEventListener(window, "mousemove", this.onGripperMouseMove);
this.events.removeEventListener(window, "mouseup", this.onGripperMouseUp);
}
}
CustomDialog.defaultProps = {
contentJustification: ContentJustification.Center,
contentLocation: ContentLocation.Center,
escDismiss: true,
lightDismiss: true,
enterPrimary: true
};
CustomDialog.contextType = ScreenContext;