UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

132 lines (131 loc) 8.29 kB
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;