@sap-ux/ui-components
Version:
SAP UI Components Library
283 lines • 10.9 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UIDialog = exports.UIDialogScrollArea = exports.DIALOG_STYLES = exports.DIALOG_MAX_HEIGHT_OFFSET = void 0;
const react_1 = __importDefault(require("react"));
const react_2 = require("@fluentui/react");
const UIButton_1 = require("../UIButton");
const DeepMerge_1 = require("../../utilities/DeepMerge");
require("../../styles/_shadows.scss");
exports.DIALOG_MAX_HEIGHT_OFFSET = 32;
exports.DIALOG_STYLES = {
background: 'var(--vscode-editorWidget-background)',
boxShadow: 'var(--ui-box-shadow-medium)',
borderColor: 'var(--vscode-editorWidget-border)',
borderRadius: 4,
vPadding: 20,
vPaddingHalf: 10,
hPadding: 45,
title: {
color: 'var(--vscode-panelTitle-activeForeground)'
},
contentText: {
fontSize: 13,
color: 'var(--vscode-foreground)',
fontFamily: 'var(--vscode-font-family)'
}
};
var UIDialogScrollArea;
(function (UIDialogScrollArea) {
// Header and footer freezed and content is scrollable
UIDialogScrollArea["Content"] = "Content";
// Whole dialog is scrollable - default FluentUI behaviour, but it is buggy with large content
UIDialogScrollArea["Dialog"] = "Dialog";
})(UIDialogScrollArea || (exports.UIDialogScrollArea = UIDialogScrollArea = {}));
/**
* UIDialog component.
* based on https://developer.microsoft.com/en-us/fluentui#/controls/web/dialog
* and https://app.abstract.com/projects/42046ab5-889d-4a59-88e6-1089e98cba67/branches/master/commits/f1fcd77447bb2b32aab3498311c1c39517e47e49/files/1455D538-559B-48EF-8D9F-1C2884ED540B/layers/AFDAAFD3-BFA6-4E96-BB6D-057DD13753E5
*
* @exports
* @class UIDialog
* @extends {React.Component<IDialogProps, {}>}
*/
class UIDialog extends react_1.default.Component {
/**
* Initializes component properties.
*
* @param {DialogProps} props
*/
constructor(props) {
super(props);
this.onResize = this.onResize.bind(this);
this.onModalLayerMount = this.onModalLayerMount.bind(this);
this.onModalLayerUnmount = this.onModalLayerUnmount.bind(this);
this.attachResize = this.attachResize.bind(this);
this.detachResize = this.detachResize.bind(this);
this.onHeaderMouseDown = this.onHeaderMouseDown.bind(this);
this.state = {
resizeMaxHeight: this.getResizeMaxHeight(),
isMounted: false
};
}
/**
* Called when component is rerendered.
*
* @param {Readonly<DialogProps>} prevProps
*/
componentDidUpdate(prevProps) {
const { scrollArea } = this.props;
if (prevProps.scrollArea !== scrollArea) {
if (scrollArea === UIDialogScrollArea.Content) {
this.attachResize();
}
else {
this.detachResize();
}
}
}
/**
* Method handles modal dialog mount event.
*/
onModalLayerMount() {
this.attachResize();
this.setState({
isMounted: true
});
}
/**
* Method handles modal dialog unmount event.
*/
onModalLayerUnmount() {
this.detachResize();
this.setState({
isMounted: false
});
}
/**
* Method attaches to window resize event.
*/
attachResize() {
// Window resize handled
window.addEventListener('resize', this.onResize);
this.onResize();
}
/**
* Method detaches from window resize event.
*/
detachResize() {
window.removeEventListener('resize', this.onResize);
}
/**
* Method handles window resizer event to update calculation for content scrollarea size.
*/
onResize() {
this.setState({
resizeMaxHeight: this.getResizeMaxHeight()
});
}
/**
* Method returns maximal height for dialog content "scrollArea=Content" mode.
*
* @returns {number} Max size of dialog.
*/
getResizeMaxHeight() {
return window.innerHeight - exports.DIALOG_MAX_HEIGHT_OFFSET;
}
/**
* Method returns footer element depending in component props.
* Three states.
* 1. Accept/Decline buttons.
* 2. Custom content of footer.
* 3. No footer.
*
* @returns {JSX.Element | null} Footer element to render.
*/
getFooter() {
let element;
const { acceptButtonText, cancelButtonText, onAccept, onCancel, acceptButtonId, cancelButtonId, footer } = this.props;
const dialogFooterProps = {
styles: {
actionsRight: {
width: '100%',
textAlign: 'center',
justifyContent: 'center',
margin: '0px'
},
actions: {
margin: `${exports.DIALOG_STYLES.vPaddingHalf}px 0 ${exports.DIALOG_STYLES.vPadding}px`,
lineHeight: 'auto'
},
action: {
margin: '0px 5px'
}
}
};
if (footer) {
element = react_1.default.createElement(react_2.DialogFooter, { ...dialogFooterProps }, footer);
}
else if (onAccept || onCancel) {
element = (react_1.default.createElement(react_2.DialogFooter, { ...dialogFooterProps },
onAccept ? (react_1.default.createElement(UIButton_1.UIDefaultButton, { onClick: onAccept, primary: true, style: { height: '26px' }, id: acceptButtonId }, acceptButtonText)) : (''),
onCancel ? (react_1.default.createElement(UIButton_1.UIDefaultButton, { onClick: onCancel, style: { height: '26px' }, id: cancelButtonId }, cancelButtonText)) : ('')));
}
return element;
}
/**
* Method handles mousedown event for dialog header area.
* Method added to handle scenario when we open dropdown menu and move dialog.
* Code in method sets focus to focuszone's placeholder - it triggers close for opened dropdown menu.
*
* @param {React.MouseEvent} event Mousedown event
*/
onHeaderMouseDown(event) {
if (!this.props.modalProps?.dragOptions) {
// No need to handle non draggable
return;
}
const dialogFocusZone = event.target.closest('.ms-Dialog-main');
if (dialogFocusZone?.firstChild) {
const focusPlaceholder = dialogFocusZone.firstChild;
focusPlaceholder.focus();
}
}
/**
* @returns {JSX.Element}
*/
render() {
const { acceptButtonText, cancelButtonText, onAccept, onCancel, acceptButtonId, cancelButtonId, footer, closeButtonVisible, multiLineTitle, scrollArea = UIDialogScrollArea.Content, children, ...rest } = this.props;
const dialogProps = {
minWidth: '460px',
modalProps: {
layerProps: {
onLayerDidMount: this.onModalLayerMount,
onLayerWillUnmount: this.onModalLayerUnmount
}
},
styles: {
root: {
opacity: !this.props.isOpenAnimated || this.state.isMounted ? undefined : 0
},
main: {
backgroundColor: exports.DIALOG_STYLES.background,
border: `1px solid ${exports.DIALOG_STYLES.borderColor}`,
boxShadow: exports.DIALOG_STYLES.boxShadow,
borderRadius: exports.DIALOG_STYLES.borderRadius,
minHeight: 100,
...(scrollArea === UIDialogScrollArea.Content && {
overflow: 'hidden',
'.ms-Modal-scrollableContent': {
overflow: 'hidden',
height: '100%'
}
})
}
},
dialogContentProps: {
title: this.props.title,
titleProps: {
className: 'ui-medium-header',
style: {
padding: `${exports.DIALOG_STYLES.vPadding}px 0 5px`,
textAlign: 'center',
color: exports.DIALOG_STYLES.title.color,
...(!multiLineTitle && {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
padding: `${exports.DIALOG_STYLES.vPadding}px ${exports.DIALOG_STYLES.hPadding}px 5px`
})
},
onMouseDown: this.onHeaderMouseDown
},
styles: {
button: {
display: !closeButtonVisible ? 'none' : undefined
},
inner: {
padding: '0',
...(scrollArea === UIDialogScrollArea.Content && {
height: '100%',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column'
})
},
subText: {
margin: '0',
lineHeight: 18,
...exports.DIALOG_STYLES.contentText
},
content: {
...exports.DIALOG_STYLES.contentText,
...(scrollArea === UIDialogScrollArea.Content && {
height: '100%',
display: 'flex',
flexDirection: 'column',
maxHeight: this.state.resizeMaxHeight
})
},
innerContent: {
padding: `${exports.DIALOG_STYLES.vPaddingHalf}px ${exports.DIALOG_STYLES.hPadding}px`,
boxSizing: 'border-box',
...(scrollArea === UIDialogScrollArea.Content && {
height: '100%',
overflow: 'auto',
boxSizing: 'border-box'
})
}
}
}
};
const props = (0, DeepMerge_1.deepMerge)(dialogProps, rest);
return (react_1.default.createElement(react_2.Dialog, { ...props },
children,
this.getFooter()));
}
}
exports.UIDialog = UIDialog;
// Default values for public component properties
UIDialog.defaultProps = { isOpenAnimated: true };
//# sourceMappingURL=UIDialog.js.map