first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
@@ -0,0 +1,3 @@
import * as React from 'react';
import type { IModalProps } from './Modal.types';
export declare const ModalBase: React.FunctionComponent<IModalProps>;
@@ -0,0 +1,332 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModalBase = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var Utilities_1 = require("../../Utilities");
var FocusTrapZone_1 = require("../../FocusTrapZone");
var Modal_styles_1 = require("./Modal.styles");
var Overlay_1 = require("../../Overlay");
var Layer_1 = require("../../Layer");
var Popup_1 = require("../../Popup");
var ResponsiveMode_1 = require("../../ResponsiveMode");
var DirectionalHint_1 = require("../../common/DirectionalHint");
var Icon_1 = require("../../Icon");
var index_1 = require("../../utilities/DraggableZone/index");
var react_window_provider_1 = require("@fluentui/react-window-provider");
var react_hooks_1 = require("@fluentui/react-hooks");
var ZERO = { x: 0, y: 0 };
var DEFAULT_PROPS = {
isOpen: false,
isDarkOverlay: true,
className: '',
containerClassName: '',
enableAriaHiddenSiblings: true,
};
var getClassNames = (0, Utilities_1.classNamesFunction)();
var getMoveDelta = function (ev) {
var delta = 10;
if (ev.shiftKey) {
if (!ev.ctrlKey) {
delta = 50;
}
}
else if (ev.ctrlKey) {
delta = 1;
}
return delta;
};
var useComponentRef = function (props, focusTrapZone) {
React.useImperativeHandle(props.componentRef, function () { return ({
focus: function () {
if (focusTrapZone.current) {
focusTrapZone.current.focus();
}
},
}); }, [focusTrapZone]);
};
exports.ModalBase = React.forwardRef(function (propsWithoutDefaults, ref) {
var _a, _b, _c, _d, _e;
var props = (0, Utilities_1.getPropsWithDefaults)(DEFAULT_PROPS, propsWithoutDefaults);
var allowTouchBodyScroll = props.allowTouchBodyScroll, className = props.className, children = props.children, containerClassName = props.containerClassName, scrollableContentClassName = props.scrollableContentClassName, elementToFocusOnDismiss = props.elementToFocusOnDismiss, firstFocusableSelector = props.firstFocusableSelector, focusTrapZoneProps = props.focusTrapZoneProps, forceFocusInsideTrap = props.forceFocusInsideTrap,
// eslint-disable-next-line @typescript-eslint/no-deprecated
_f = props.disableRestoreFocus,
// eslint-disable-next-line @typescript-eslint/no-deprecated
disableRestoreFocus = _f === void 0 ? props.ignoreExternalFocusing : _f, isBlocking = props.isBlocking, isAlert = props.isAlert, isClickableOutsideFocusTrap = props.isClickableOutsideFocusTrap, isDarkOverlay = props.isDarkOverlay, onDismiss = props.onDismiss, layerProps = props.layerProps, overlay = props.overlay, isOpen = props.isOpen, titleAriaId = props.titleAriaId, styles = props.styles, subtitleAriaId = props.subtitleAriaId, theme = props.theme, topOffsetFixed = props.topOffsetFixed, responsiveMode = props.responsiveMode,
// eslint-disable-next-line @typescript-eslint/no-deprecated
onLayerDidMount = props.onLayerDidMount, isModeless = props.isModeless, dragOptions = props.dragOptions, onDismissed = props.onDismissed,
// eslint-disable-next-line @typescript-eslint/no-deprecated
enableAriaHiddenSiblings = props.enableAriaHiddenSiblings, popupProps = props.popupProps;
var rootRef = React.useRef(null);
var focusTrapZone = React.useRef(null);
var focusTrapZoneRef = (0, react_hooks_1.useMergedRefs)(focusTrapZone, focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.componentRef);
var focusTrapZoneElm = React.useRef(null);
var mergedRef = (0, react_hooks_1.useMergedRefs)(rootRef, ref);
var modalResponsiveMode = (0, ResponsiveMode_1.useResponsiveMode)(mergedRef);
var focusTrapZoneId = (0, react_hooks_1.useId)('ModalFocusTrapZone', focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.id);
var win = (0, react_window_provider_1.useWindow)();
var _g = (0, react_hooks_1.useSetTimeout)(), setTimeout = _g.setTimeout, clearTimeout = _g.clearTimeout;
var _h = React.useState(isOpen), isModalOpen = _h[0], setIsModalOpen = _h[1];
var _j = React.useState(isOpen), isVisible = _j[0], setIsVisible = _j[1];
var _k = React.useState(ZERO), coordinates = _k[0], setCoordinates = _k[1];
var _l = React.useState(), modalRectangleTop = _l[0], setModalRectangleTop = _l[1];
var _m = (0, react_hooks_1.useBoolean)(false), isModalMenuOpen = _m[0], _o = _m[1], toggleModalMenuOpen = _o.toggle, setModalMenuClose = _o.setFalse;
var internalState = (0, react_hooks_1.useConst)(function () { return ({
onModalCloseTimer: 0,
allowTouchBodyScroll: allowTouchBodyScroll,
scrollableContent: null,
lastSetCoordinates: ZERO,
events: new Utilities_1.EventGroup({}),
}); });
var keepInBounds = (dragOptions || {}).keepInBounds;
var isAlertRole = isAlert !== null && isAlert !== void 0 ? isAlert : (isBlocking && !isModeless);
var layerClassName = layerProps === undefined ? '' : layerProps.className;
var classNames = getClassNames(styles, {
theme: theme,
className: className,
containerClassName: containerClassName,
scrollableContentClassName: scrollableContentClassName,
isOpen: isOpen,
isVisible: isVisible,
hasBeenOpened: internalState.hasBeenOpened,
modalRectangleTop: modalRectangleTop,
topOffsetFixed: topOffsetFixed,
isModeless: isModeless,
layerClassName: layerClassName,
windowInnerHeight: win === null || win === void 0 ? void 0 : win.innerHeight,
isDefaultDragHandle: dragOptions && !dragOptions.dragHandleSelector,
});
var mergedLayerProps = tslib_1.__assign(tslib_1.__assign({ eventBubblingEnabled: false }, layerProps), { onLayerDidMount: layerProps && layerProps.onLayerDidMount ? layerProps.onLayerDidMount : onLayerDidMount, insertFirst: (layerProps === null || layerProps === void 0 ? void 0 : layerProps.insertFirst) || isModeless, className: classNames.layer });
// Allow the user to scroll within the modal but not on the body
var allowScrollOnModal = React.useCallback(function (elt) {
if (elt) {
if (internalState.allowTouchBodyScroll) {
(0, Utilities_1.allowOverscrollOnElement)(elt, internalState.events);
}
else {
(0, Utilities_1.allowScrollOnElement)(elt, internalState.events);
}
}
else {
internalState.events.off(internalState.scrollableContent);
}
internalState.scrollableContent = elt;
}, [internalState]);
var registerInitialModalPosition = function () {
var dialogMain = focusTrapZoneElm.current;
var modalRectangle = dialogMain === null || dialogMain === void 0 ? void 0 : dialogMain.getBoundingClientRect();
if (modalRectangle) {
if (topOffsetFixed) {
setModalRectangleTop(modalRectangle.top);
}
if (keepInBounds) {
// x/y are unavailable in IE, so use the equivalent left/top
internalState.minPosition = { x: -modalRectangle.left, y: -modalRectangle.top };
internalState.maxPosition = { x: modalRectangle.left, y: modalRectangle.top };
}
}
};
/**
* Clamps an axis to a specified min and max position.
*
* @param axis A string that represents the axis (x/y).
* @param position The position on the axis.
*/
var getClampedAxis = React.useCallback(function (axis, position) {
var minPosition = internalState.minPosition, maxPosition = internalState.maxPosition;
if (keepInBounds && minPosition && maxPosition) {
position = Math.max(minPosition[axis], position);
position = Math.min(maxPosition[axis], position);
}
return position;
}, [keepInBounds, internalState]);
var handleModalClose = function () {
var _a;
internalState.lastSetCoordinates = ZERO;
setModalMenuClose();
internalState.isInKeyboardMoveMode = false;
setIsModalOpen(false);
setCoordinates(ZERO);
(_a = internalState.disposeOnKeyUp) === null || _a === void 0 ? void 0 : _a.call(internalState);
onDismissed === null || onDismissed === void 0 ? void 0 : onDismissed();
};
var handleDragStart = React.useCallback(function () {
setModalMenuClose();
internalState.isInKeyboardMoveMode = false;
}, [internalState, setModalMenuClose]);
var handleDrag = React.useCallback(function (ev, dragData) {
setCoordinates(function (prevValue) { return ({
x: getClampedAxis('x', prevValue.x + dragData.delta.x),
y: getClampedAxis('y', prevValue.y + dragData.delta.y),
}); });
}, [getClampedAxis]);
var handleDragStop = React.useCallback(function () {
if (focusTrapZone.current) {
focusTrapZone.current.focus();
}
}, []);
var handleEnterKeyboardMoveMode = function () {
// We need a global handleKeyDown event when we are in the move mode so that we can
// handle the key presses and the components inside the modal do not get the events
var handleKeyDown = function (ev) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
if (ev.altKey && ev.ctrlKey && ev.keyCode === Utilities_1.KeyCodes.space) {
// CTRL + ALT + SPACE is handled during keyUp
ev.preventDefault();
ev.stopPropagation();
return;
}
// eslint-disable-next-line @typescript-eslint/no-deprecated
var newLocal = ev.altKey || ev.keyCode === Utilities_1.KeyCodes.escape;
if (isModalMenuOpen && newLocal) {
setModalMenuClose();
}
// eslint-disable-next-line @typescript-eslint/no-deprecated
if (internalState.isInKeyboardMoveMode && (ev.keyCode === Utilities_1.KeyCodes.escape || ev.keyCode === Utilities_1.KeyCodes.enter)) {
internalState.isInKeyboardMoveMode = false;
ev.preventDefault();
ev.stopPropagation();
}
if (internalState.isInKeyboardMoveMode) {
var handledEvent = true;
var delta_1 = getMoveDelta(ev);
// eslint-disable-next-line @typescript-eslint/no-deprecated
switch (ev.keyCode) {
/* eslint-disable no-fallthrough */
case Utilities_1.KeyCodes.escape:
setCoordinates(internalState.lastSetCoordinates);
case Utilities_1.KeyCodes.enter: {
// TODO: determine if fallthrough was intentional
/* eslint-enable no-fallthrough */
internalState.lastSetCoordinates = ZERO;
// setIsInKeyboardMoveMode(false);
break;
}
case Utilities_1.KeyCodes.up: {
setCoordinates(function (prevValue) { return ({ x: prevValue.x, y: getClampedAxis('y', prevValue.y - delta_1) }); });
break;
}
case Utilities_1.KeyCodes.down: {
setCoordinates(function (prevValue) { return ({ x: prevValue.x, y: getClampedAxis('y', prevValue.y + delta_1) }); });
break;
}
case Utilities_1.KeyCodes.left: {
setCoordinates(function (prevValue) { return ({ x: getClampedAxis('x', prevValue.x - delta_1), y: prevValue.y }); });
break;
}
case Utilities_1.KeyCodes.right: {
setCoordinates(function (prevValue) { return ({ x: getClampedAxis('x', prevValue.x + delta_1), y: prevValue.y }); });
break;
}
default: {
handledEvent = false;
}
}
if (handledEvent) {
ev.preventDefault();
ev.stopPropagation();
}
}
};
internalState.lastSetCoordinates = coordinates;
setModalMenuClose();
internalState.isInKeyboardMoveMode = true;
internalState.events.on(win, 'keydown', handleKeyDown, true /* useCapture */);
internalState.disposeOnKeyDown = function () {
internalState.events.off(win, 'keydown', handleKeyDown, true /* useCapture */);
internalState.disposeOnKeyDown = undefined;
};
};
var handleExitKeyboardMoveMode = function (ev) {
var _a, _b;
(_a = focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(focusTrapZoneProps, ev);
internalState.lastSetCoordinates = ZERO;
internalState.isInKeyboardMoveMode = false;
(_b = internalState.disposeOnKeyDown) === null || _b === void 0 ? void 0 : _b.call(internalState);
};
var registerForKeyUp = function () {
var handleKeyUp = function (ev) {
// Needs to handle the CTRL + ALT + SPACE key during keyup due to FireFox bug:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
// eslint-disable-next-line @typescript-eslint/no-deprecated
if (ev.altKey && ev.ctrlKey && ev.keyCode === Utilities_1.KeyCodes.space) {
if ((0, Utilities_1.elementContains)(internalState.scrollableContent, ev.target)) {
toggleModalMenuOpen();
ev.preventDefault();
ev.stopPropagation();
}
}
};
if (!internalState.disposeOnKeyUp) {
internalState.events.on(win, 'keyup', handleKeyUp, true /* useCapture */);
internalState.disposeOnKeyUp = function () {
internalState.events.off(win, 'keyup', handleKeyUp, true /* useCapture */);
internalState.disposeOnKeyUp = undefined;
};
}
};
React.useEffect(function () {
clearTimeout(internalState.onModalCloseTimer);
// Opening the dialog
if (isOpen) {
// This must be done after the modal content has rendered
requestAnimationFrame(function () { return setTimeout(registerInitialModalPosition, 0); });
setIsModalOpen(true);
// Add a keyUp handler for all key up events once the dialog is open.
if (dragOptions) {
registerForKeyUp();
}
internalState.hasBeenOpened = true;
setIsVisible(true);
}
// Closing the dialog
if (!isOpen && isModalOpen) {
internalState.onModalCloseTimer = setTimeout(handleModalClose, parseFloat(Modal_styles_1.animationDuration) * 1000);
setIsVisible(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps -- should only run if isModalOpen or isOpen mutates.
}, [isModalOpen, isOpen]);
(0, react_hooks_1.useUnmount)(function () {
internalState.events.dispose();
if (internalState.onModalCloseTimer) {
clearTimeout(internalState.onModalCloseTimer);
internalState.onModalCloseTimer = 0;
}
});
useComponentRef(props, focusTrapZone);
useDebugWarnings(props);
var modalContent = (React.createElement(FocusTrapZone_1.FocusTrapZone, tslib_1.__assign({}, focusTrapZoneProps, { id: focusTrapZoneId, ref: focusTrapZoneElm, componentRef: focusTrapZoneRef, className: (0, Utilities_1.css)(classNames.main, focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.className), elementToFocusOnDismiss: (_a = focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.elementToFocusOnDismiss) !== null && _a !== void 0 ? _a : elementToFocusOnDismiss, isClickableOutsideFocusTrap: (_b = focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.isClickableOutsideFocusTrap) !== null && _b !== void 0 ? _b : (isModeless || isClickableOutsideFocusTrap || !isBlocking), disableRestoreFocus: (_c = focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.disableRestoreFocus) !== null && _c !== void 0 ? _c : disableRestoreFocus, forceFocusInsideTrap: ((_d = focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.forceFocusInsideTrap) !== null && _d !== void 0 ? _d : forceFocusInsideTrap) && !isModeless,
// eslint-disable-next-line @typescript-eslint/no-deprecated
firstFocusableSelector: (focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.firstFocusableSelector) || firstFocusableSelector, focusPreviouslyFocusedInnerElement: (_e = focusTrapZoneProps === null || focusTrapZoneProps === void 0 ? void 0 : focusTrapZoneProps.focusPreviouslyFocusedInnerElement) !== null && _e !== void 0 ? _e : true, onBlur: internalState.isInKeyboardMoveMode ? handleExitKeyboardMoveMode : undefined }),
dragOptions && internalState.isInKeyboardMoveMode && (React.createElement("div", { className: classNames.keyboardMoveIconContainer }, dragOptions.keyboardMoveIconProps ? (React.createElement(Icon_1.Icon, tslib_1.__assign({}, dragOptions.keyboardMoveIconProps))) : (React.createElement(Icon_1.Icon, { iconName: "move", className: classNames.keyboardMoveIcon })))),
React.createElement("div", { ref: allowScrollOnModal, className: classNames.scrollableContent, "data-is-scrollable": true },
dragOptions && isModalMenuOpen && (React.createElement(dragOptions.menu, { items: [
{ key: 'move', text: dragOptions.moveMenuItemText, onClick: handleEnterKeyboardMoveMode },
{ key: 'close', text: dragOptions.closeMenuItemText, onClick: handleModalClose },
], onDismiss: setModalMenuClose, alignTargetEdge: true, coverTarget: true, directionalHint: DirectionalHint_1.DirectionalHint.topLeftEdge, directionalHintFixed: true, shouldFocusOnMount: true, target: internalState.scrollableContent })),
children)));
return ((isModalOpen && modalResponsiveMode >= (responsiveMode || ResponsiveMode_1.ResponsiveMode.small) && (React.createElement(Layer_1.Layer, tslib_1.__assign({ ref: mergedRef }, mergedLayerProps),
React.createElement(Popup_1.Popup, tslib_1.__assign({ role: isAlertRole ? 'alertdialog' : 'dialog', ariaLabelledBy: titleAriaId, ariaDescribedBy: subtitleAriaId, onDismiss: onDismiss,
// eslint-disable-next-line @typescript-eslint/no-deprecated
shouldRestoreFocus: !disableRestoreFocus,
// Modeless modals shouldn't hide siblings.
// Popup will automatically handle this based on the aria-modal setting.
// eslint-disable-next-line @typescript-eslint/no-deprecated
enableAriaHiddenSiblings: enableAriaHiddenSiblings, "aria-modal": !isModeless }, popupProps),
React.createElement("div", { className: classNames.root, role: !isModeless ? 'document' : undefined },
!isModeless && (React.createElement(Overlay_1.Overlay, tslib_1.__assign({ "aria-hidden": true, isDarkThemed: isDarkOverlay, onClick: isBlocking ? undefined : onDismiss, allowTouchBodyScroll: allowTouchBodyScroll }, overlay))),
dragOptions ? (React.createElement(index_1.DraggableZone, { handleSelector: dragOptions.dragHandleSelector || "#".concat(focusTrapZoneId), preventDragSelector: "button", onStart: handleDragStart, onDragChange: handleDrag, onStop: handleDragStop, position: coordinates }, modalContent)) : (modalContent)))))) ||
null);
});
exports.ModalBase.displayName = 'Modal';
function useDebugWarnings(props) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line react-hooks/rules-of-hooks -- build-time conditional
(0, react_hooks_1.useWarnings)({
name: 'Modal',
props: props,
deprecations: { onLayerDidMount: 'layerProps.onLayerDidMount' },
});
}
}
//# sourceMappingURL=Modal.base.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
import * as React from 'react';
import type { IModalProps } from './Modal.types';
export declare const Modal: React.FunctionComponent<IModalProps>;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Modal = void 0;
var Utilities_1 = require("../../Utilities");
var Modal_base_1 = require("./Modal.base");
var Modal_styles_1 = require("./Modal.styles");
exports.Modal = (0, Utilities_1.styled)(Modal_base_1.ModalBase, Modal_styles_1.getStyles, undefined, {
scope: 'Modal',
fields: ['theme', 'styles', 'enableAriaHiddenSiblings'],
});
exports.Modal.displayName = 'Modal';
//# sourceMappingURL=Modal.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Modal.js","sourceRoot":"../src/","sources":["components/Modal/Modal.ts"],"names":[],"mappings":";;;AACA,6CAAyC;AACzC,2CAAyC;AACzC,+CAA2C;AAG9B,QAAA,KAAK,GAAyC,IAAA,kBAAM,EAC/D,sBAAS,EACT,wBAAS,EACT,SAAS,EACT;IACE,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,0BAA0B,CAAC;CACxD,CACF,CAAC;AACF,aAAK,CAAC,WAAW,GAAG,OAAO,CAAC","sourcesContent":["import * as React from 'react';\nimport { styled } from '../../Utilities';\nimport { ModalBase } from './Modal.base';\nimport { getStyles } from './Modal.styles';\nimport type { IModalProps, IModalStyleProps, IModalStyles } from './Modal.types';\n\nexport const Modal: React.FunctionComponent<IModalProps> = styled<IModalProps, IModalStyleProps, IModalStyles>(\n ModalBase,\n getStyles,\n undefined,\n {\n scope: 'Modal',\n fields: ['theme', 'styles', 'enableAriaHiddenSiblings'],\n },\n);\nModal.displayName = 'Modal';\n"]}
@@ -0,0 +1,3 @@
import type { IModalStyleProps, IModalStyles } from './Modal.types';
export declare const animationDuration: string;
export declare const getStyles: (props: IModalStyleProps) => IModalStyles;
@@ -0,0 +1,109 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStyles = exports.animationDuration = void 0;
var Styling_1 = require("../../Styling");
exports.animationDuration = Styling_1.AnimationVariables.durationValue2;
var globalClassNames = {
root: 'ms-Modal',
main: 'ms-Dialog-main',
scrollableContent: 'ms-Modal-scrollableContent',
isOpen: 'is-open',
layer: 'ms-Modal-Layer',
};
var getStyles = function (props) {
var _a;
var className = props.className, containerClassName = props.containerClassName, scrollableContentClassName = props.scrollableContentClassName, isOpen = props.isOpen, isVisible = props.isVisible, hasBeenOpened = props.hasBeenOpened, modalRectangleTop = props.modalRectangleTop, theme = props.theme, topOffsetFixed = props.topOffsetFixed, isModeless = props.isModeless, layerClassName = props.layerClassName, isDefaultDragHandle = props.isDefaultDragHandle, windowInnerHeight = props.windowInnerHeight;
var palette = theme.palette, effects = theme.effects, fonts = theme.fonts;
var classNames = (0, Styling_1.getGlobalClassNames)(globalClassNames, theme);
return {
root: [
classNames.root,
fonts.medium,
{
backgroundColor: 'transparent',
position: 'fixed',
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
opacity: 0,
pointerEvents: 'none',
transition: "opacity ".concat(exports.animationDuration),
},
topOffsetFixed &&
typeof modalRectangleTop === 'number' &&
hasBeenOpened && {
alignItems: 'flex-start',
},
isOpen && classNames.isOpen,
isVisible && {
opacity: 1,
},
isVisible &&
!isModeless && {
pointerEvents: 'auto',
},
className,
],
main: [
classNames.main,
{
boxShadow: effects.elevation64,
borderRadius: effects.roundedCorner2,
backgroundColor: palette.white,
boxSizing: 'border-box',
position: 'relative',
textAlign: 'left',
outline: '3px solid transparent',
maxHeight: 'calc(100% - 32px)',
maxWidth: 'calc(100% - 32px)',
minHeight: '176px',
minWidth: '288px',
overflowY: 'auto',
zIndex: isModeless ? Styling_1.ZIndexes.Layer : undefined,
},
isModeless && {
pointerEvents: 'auto',
},
topOffsetFixed &&
typeof modalRectangleTop === 'number' &&
hasBeenOpened && {
top: modalRectangleTop,
},
isDefaultDragHandle && {
cursor: 'move',
},
containerClassName,
],
scrollableContent: [
classNames.scrollableContent,
{
overflowY: 'auto',
flexGrow: 1,
maxHeight: '100vh',
selectors: (_a = {},
_a['@supports (-webkit-overflow-scrolling: touch)'] = {
maxHeight: windowInnerHeight,
},
_a),
},
scrollableContentClassName,
],
layer: isModeless && [layerClassName, classNames.layer, { pointerEvents: 'none' }],
keyboardMoveIconContainer: {
position: 'absolute',
display: 'flex',
justifyContent: 'center',
width: '100%',
padding: '3px 0px',
},
keyboardMoveIcon: {
// eslint-disable-next-line @typescript-eslint/no-deprecated
fontSize: fonts.xLargePlus.fontSize,
width: '24px',
},
};
};
exports.getStyles = getStyles;
//# sourceMappingURL=Modal.styles.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,201 @@
import * as React from 'react';
import { ResponsiveMode } from '../../ResponsiveMode';
import type { IAccessiblePopupProps } from '../../common/IAccessiblePopupProps';
import type { IContextualMenuProps } from '../../ContextualMenu';
import type { IFocusTrapZoneProps } from '../../FocusTrapZone';
import type { IIconProps } from '../../Icon';
import type { ILayerProps } from '../../Layer';
import type { IOverlayProps } from '../../Overlay';
import type { IStyle, ITheme } from '../../Styling';
import type { IRefObject, IStyleFunctionOrObject } from '../../Utilities';
import { IPopupProps } from '../Popup/Popup.types';
export interface IDragOptions {
/**
* Optional selector for the element where the drag can be initiated. If not supplied when
* isDraggable is true dragging can be initiated by the whole contents of the modal
*/
dragHandleSelector?: string;
/**
* IconProps for the icon used to indicate that the dialog is in keyboard move mode
*/
keyboardMoveIconProps?: IIconProps;
/**
* The text to use for the modal move menu item
*/
moveMenuItemText: string;
/**
* The text to use for the modal close menu item
*/
closeMenuItemText: string;
/**
* The Draggable Control Menu so that the draggable zone can be moved via the keyboard
*/
menu: React.FunctionComponent<IContextualMenuProps>;
/**
* Whether the draggable content should be prevented from going off-screen
*/
keepInBounds?: boolean;
}
/**
* {@docCategory Modal}
*/
export interface IModal {
/**
* Sets focus on the first focusable, or configured, child in focus trap zone
*/
focus: () => void;
}
/**
* {@docCategory Modal}
*/
export interface IModalProps extends React.RefAttributes<HTMLDivElement>, IAccessiblePopupProps {
children?: React.ReactNode;
/**
* Optional ref to access the `IModal` interface. Use this instead of `ref` for accessing
* public API of the component.
*/
componentRef?: IRefObject<IModal>;
/**
* Call to provide customized styling that will layer on top of the variant rules.
*/
styles?: IStyleFunctionOrObject<IModalStyleProps, IModalStyles>;
/**
* Theme provided by higher-order component.
*/
theme?: ITheme;
/**
* Whether the dialog is displayed.
* @default false
*/
isOpen?: boolean;
/**
* Whether the overlay is dark themed.
* @default true
*/
isDarkOverlay?: boolean;
/**
* A callback function for when the Modal is dismissed light dismiss, before the animation completes.
*/
onDismiss?: (ev?: React.MouseEvent<HTMLButtonElement | HTMLElement>) => any;
/**
* A callback function which is called after the Modal is dismissed and the animation is complete.
*/
onDismissed?: () => any;
/**
* The specified responsiveMode value for Modal to use.
* @default ResponsiveMode.small
*/
responsiveMode?: ResponsiveMode;
/**
* Defines an optional set of props to be passed through to Layer
*/
layerProps?: ILayerProps;
/**
* Defines an optional set of props to be passed through to Overlay
*/
overlay?: IOverlayProps;
/**
* Whether the dialog can be light dismissed by clicking outside the dialog (on the overlay).
* @default false
*/
isBlocking?: boolean;
/**
* Whether the dialog should be modeless (e.g. not dismiss when focusing/clicking outside of the dialog).
* if true: isBlocking is ignored, there will be no overlay (isDarkOverlay is ignored),
* isClickableOutsideFocusTrap is true, and forceFocusInsideTrap is false
*/
isModeless?: boolean;
/**
* Determines the ARIA role of the dialog (alertdialog/dialog)
* If this is set, it will override the ARIA role determined by isBlocking and isModeless
*
* For more information regarding dialogs please see https://w3c.github.io/aria-practices/#alertdialog
*/
isAlert?: boolean;
/**
* Optional class name to be added to the root class
*/
className?: string;
/**
* Optional override for container class
*/
containerClassName?: string;
/**
* Optional override for scrollable content class
*/
scrollableContentClassName?: string;
/**
* A callback function for when the Modal content is mounted on the overlay layer
* @deprecated Use `layerProps.onLayerDidMount` instead
*/
onLayerDidMount?: () => void;
/**
* ARIA id for the title of the Modal, if any
*/
titleAriaId?: string;
/**
* ARIA id for the subtitle of the Modal, if any
*/
subtitleAriaId?: string;
/**
* Whether the modal should have top offset fixed once opened and expand from the bottom only
* when the content changes dynamically.
*/
topOffsetFixed?: boolean;
/**
* The options to make the modal draggable
*/
dragOptions?: IDragOptions;
/**
* Allow body scroll on content and overlay on touch devices. Changing after mounting has no effect.
* @default false
*/
allowTouchBodyScroll?: boolean;
/**
* Puts aria-hidden=true on all non-ancestors of the current modal, for screen readers
* (unless `isModeless` is true).
* @default true
* @deprecated Setting this to `false` is deprecated since it breaks modal behavior for some screen readers.
* It will not be supported in future versions of the library (except for modeless modals).
*/
enableAriaHiddenSiblings?: boolean;
/**
* Set of props to customize the `FocusTrapZone` inside of the `Modal`.
* @default `{}`
*/
focusTrapZoneProps?: IFocusTrapZoneProps;
/**
* Props to be passed through to Popup
*/
popupProps?: IPopupProps;
}
/**
* {@docCategory Modal}
*/
export type IModalStyleProps = Required<Pick<IModalProps, 'theme'>> & Pick<IModalProps, 'className' | 'containerClassName' | 'scrollableContentClassName' | 'topOffsetFixed' | 'isModeless'> & {
/** Modal open state. */
isOpen?: boolean;
/** Modal visible state. */
isVisible?: boolean;
/** Modal has been opened state. */
hasBeenOpened?: boolean;
/** Positioning of modal on first render */
modalRectangleTop?: number;
/** Classname for layer element */
layerClassName?: string;
/** Whether this modal is draggable and using the default handler */
isDefaultDragHandle?: boolean;
/** The windows inner height */
windowInnerHeight?: number;
};
/**
* {@docCategory Modal}
*/
export interface IModalStyles {
root: IStyle;
main: IStyle;
scrollableContent: IStyle;
layer: IStyle;
keyboardMoveIconContainer: IStyle;
keyboardMoveIcon: IStyle;
}
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=Modal.types.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
export * from './Modal';
export * from './Modal.base';
export * from './Modal.types';
export type { IAccessiblePopupProps } from '../../common/IAccessiblePopupProps';
+7
View File
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./Modal"), exports);
tslib_1.__exportStar(require("./Modal.base"), exports);
tslib_1.__exportStar(require("./Modal.types"), exports);
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["components/Modal/index.ts"],"names":[],"mappings":";;;AAAA,kDAAwB;AACxB,uDAA6B;AAC7B,wDAA8B","sourcesContent":["export * from './Modal';\nexport * from './Modal.base';\nexport * from './Modal.types';\nexport type { IAccessiblePopupProps } from '../../common/IAccessiblePopupProps';\n"]}