464 lines
28 KiB
JavaScript
464 lines
28 KiB
JavaScript
define(["require", "exports", "tslib", "react", "../../common/DirectionalHint", "../../Utilities", "../../utilities/positioning/positioning", "../../Positioning", "../../Popup", "../../Utilities", "../../Styling", "@fluentui/react-hooks", "../../utilities/dom"], function (require, exports, tslib_1, React, DirectionalHint_1, Utilities_1, positioning_1, Positioning_1, Popup_1, Utilities_2, Styling_1, react_hooks_1, dom_1) {
|
|
"use strict";
|
|
var _a;
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.CalloutContentBase = void 0;
|
|
var COMPONENT_NAME = 'CalloutContentBase';
|
|
var ANIMATIONS = (_a = {},
|
|
_a[Positioning_1.RectangleEdge.top] = Styling_1.AnimationClassNames.slideUpIn10,
|
|
_a[Positioning_1.RectangleEdge.bottom] = Styling_1.AnimationClassNames.slideDownIn10,
|
|
_a[Positioning_1.RectangleEdge.left] = Styling_1.AnimationClassNames.slideLeftIn10,
|
|
_a[Positioning_1.RectangleEdge.right] = Styling_1.AnimationClassNames.slideRightIn10,
|
|
_a);
|
|
var BEAK_ORIGIN_POSITION = { top: 0, left: 0 };
|
|
// Microsoft Edge will overwrite inline styles if there is an animation pertaining to that style.
|
|
// To help ensure that edge will respect the offscreen style opacity
|
|
// filter needs to be added as an additional way to set opacity.
|
|
// Also set pointer-events: none so that the callout will not occlude the element it is
|
|
// going to be positioned against
|
|
var OFF_SCREEN_STYLE = {
|
|
opacity: 0,
|
|
filter: 'opacity(0)',
|
|
pointerEvents: 'none',
|
|
};
|
|
// role and role description go hand-in-hand. Both would be included by spreading getNativeProps for a basic element
|
|
// This constant array can be used to filter these out of native props spread on callout root and apply them together on
|
|
// calloutMain (the Popup component within the callout)
|
|
var ARIA_ROLE_ATTRIBUTES = ['role', 'aria-roledescription'];
|
|
var DEFAULT_PROPS = {
|
|
preventDismissOnLostFocus: false,
|
|
preventDismissOnScroll: false,
|
|
preventDismissOnResize: false,
|
|
isBeakVisible: true,
|
|
beakWidth: 16,
|
|
gapSpace: 0,
|
|
minPagePadding: 8,
|
|
directionalHint: DirectionalHint_1.DirectionalHint.bottomAutoEdge,
|
|
};
|
|
var getClassNames = (0, Utilities_2.classNamesFunction)({
|
|
disableCaching: true, // disabling caching because stylesProp.position mutates often
|
|
});
|
|
/**
|
|
* (Hook) to return a function to lazily fetch the bounds of the target element for the callout.
|
|
*/
|
|
function useBounds(_a, targetRef, targetWindow) {
|
|
var bounds = _a.bounds, _b = _a.minPagePadding, minPagePadding = _b === void 0 ? DEFAULT_PROPS.minPagePadding : _b, target = _a.target;
|
|
var _c = React.useState(false), targetWindowResized = _c[0], setTargetWindowResized = _c[1];
|
|
var cachedBounds = React.useRef(undefined);
|
|
var getBounds = React.useCallback(function () {
|
|
if (!cachedBounds.current || targetWindowResized) {
|
|
var currentBounds = typeof bounds === 'function' ? (targetWindow ? bounds(target, targetWindow) : undefined) : bounds;
|
|
if (!currentBounds && targetWindow) {
|
|
currentBounds = (0, Positioning_1.getBoundsFromTargetWindow)(targetRef.current, targetWindow);
|
|
currentBounds = {
|
|
top: currentBounds.top + minPagePadding,
|
|
left: currentBounds.left + minPagePadding,
|
|
right: currentBounds.right - minPagePadding,
|
|
bottom: currentBounds.bottom - minPagePadding,
|
|
width: currentBounds.width - minPagePadding * 2,
|
|
height: currentBounds.height - minPagePadding * 2,
|
|
};
|
|
}
|
|
cachedBounds.current = currentBounds;
|
|
targetWindowResized && setTargetWindowResized(false);
|
|
}
|
|
return cachedBounds.current;
|
|
}, [bounds, minPagePadding, target, targetRef, targetWindow, targetWindowResized]);
|
|
var async = (0, react_hooks_1.useAsync)();
|
|
(0, react_hooks_1.useOnEvent)(targetWindow, 'resize', async.debounce(function () {
|
|
setTargetWindowResized(true);
|
|
}, 500, { leading: true }));
|
|
return getBounds;
|
|
}
|
|
/**
|
|
* (Hook) to return the maximum available height for the Callout to render into.
|
|
*/
|
|
function useMaxHeight(_a, getBounds, targetRef, positions) {
|
|
var _b;
|
|
var calloutMaxHeight = _a.calloutMaxHeight, finalHeight = _a.finalHeight, directionalHint = _a.directionalHint, directionalHintFixed = _a.directionalHintFixed, hidden = _a.hidden, gapSpace = _a.gapSpace, beakWidth = _a.beakWidth, isBeakVisible = _a.isBeakVisible, coverTarget = _a.coverTarget;
|
|
var _c = React.useState(), maxHeight = _c[0], setMaxHeight = _c[1];
|
|
var _d = (_b = positions === null || positions === void 0 ? void 0 : positions.elementPosition) !== null && _b !== void 0 ? _b : {}, top = _d.top, bottom = _d.bottom;
|
|
var targetRect = (targetRef === null || targetRef === void 0 ? void 0 : targetRef.current) ? (0, positioning_1.getRectangleFromTarget)(targetRef.current) : undefined;
|
|
React.useEffect(function () {
|
|
var _a;
|
|
var bounds = (_a = getBounds()) !== null && _a !== void 0 ? _a : {};
|
|
var topBounds = bounds.top;
|
|
var bottomBounds = bounds.bottom;
|
|
var calculatedHeight;
|
|
// If aligned to top edge of target and not covering target, update bottom bounds to the
|
|
// top of the target (accounting for gap space and beak)
|
|
if ((positions === null || positions === void 0 ? void 0 : positions.targetEdge) === Positioning_1.RectangleEdge.top && (targetRect === null || targetRect === void 0 ? void 0 : targetRect.top) && !coverTarget) {
|
|
bottomBounds = targetRect.top - (0, positioning_1.calculateGapSpace)(isBeakVisible, beakWidth, gapSpace);
|
|
}
|
|
if (typeof top === 'number' && bottomBounds) {
|
|
calculatedHeight = bottomBounds - top;
|
|
}
|
|
else if (typeof bottom === 'number' && typeof topBounds === 'number' && bottomBounds) {
|
|
calculatedHeight = bottomBounds - topBounds - bottom;
|
|
}
|
|
if ((!calloutMaxHeight && !hidden) ||
|
|
(calloutMaxHeight && calculatedHeight && calloutMaxHeight > calculatedHeight)) {
|
|
setMaxHeight(calculatedHeight);
|
|
}
|
|
else if (calloutMaxHeight) {
|
|
setMaxHeight(calloutMaxHeight);
|
|
}
|
|
else {
|
|
setMaxHeight(undefined);
|
|
}
|
|
}, [
|
|
bottom,
|
|
calloutMaxHeight,
|
|
finalHeight,
|
|
directionalHint,
|
|
directionalHintFixed,
|
|
getBounds,
|
|
hidden,
|
|
positions,
|
|
top,
|
|
gapSpace,
|
|
beakWidth,
|
|
isBeakVisible,
|
|
targetRect,
|
|
coverTarget,
|
|
]);
|
|
return maxHeight;
|
|
}
|
|
/**
|
|
* (Hook) to find the current position of Callout. If Callout is resized then a new position is calculated.
|
|
*/
|
|
function usePositions(props, hostElement, calloutElement, targetRef, getBounds, popupRef) {
|
|
var _a = React.useState(), positions = _a[0], setPositions = _a[1];
|
|
var positionAttempts = React.useRef(0);
|
|
var previousTarget = React.useRef(undefined);
|
|
var async = (0, react_hooks_1.useAsync)();
|
|
var hidden = props.hidden, target = props.target, finalHeight = props.finalHeight, calloutMaxHeight = props.calloutMaxHeight, onPositioned = props.onPositioned, directionalHint = props.directionalHint, hideOverflow = props.hideOverflow, preferScrollResizePositioning = props.preferScrollResizePositioning;
|
|
var win = (0, dom_1.useWindowEx)();
|
|
var localRef = React.useRef(undefined);
|
|
var popupStyles;
|
|
if (localRef.current !== popupRef.current) {
|
|
localRef.current = popupRef.current;
|
|
popupStyles = popupRef.current ? win === null || win === void 0 ? void 0 : win.getComputedStyle(popupRef.current) : undefined;
|
|
}
|
|
var popupOverflowY = popupStyles === null || popupStyles === void 0 ? void 0 : popupStyles.overflowY;
|
|
React.useEffect(function () {
|
|
if (!hidden) {
|
|
var timerId_1 = async.requestAnimationFrame(function () {
|
|
var _a, _b;
|
|
if (hostElement.current && calloutElement) {
|
|
var currentProps = tslib_1.__assign(tslib_1.__assign({}, props), { target: targetRef.current, bounds: getBounds() });
|
|
// duplicate calloutElement & remove useMaxHeight's maxHeight for position calc
|
|
var dupeCalloutElement = calloutElement.cloneNode(true);
|
|
dupeCalloutElement.style.maxHeight = calloutMaxHeight ? "".concat(calloutMaxHeight) : '';
|
|
dupeCalloutElement.style.visibility = 'hidden';
|
|
(_a = calloutElement.parentElement) === null || _a === void 0 ? void 0 : _a.appendChild(dupeCalloutElement);
|
|
var previousPositions = previousTarget.current === target ? positions : undefined;
|
|
// only account for scroll resizing if styles allow callout to scroll
|
|
// (popup styles determine if callout will scroll)
|
|
var isOverflowYHidden = hideOverflow || popupOverflowY === 'clip' || popupOverflowY === 'hidden';
|
|
var shouldScroll = preferScrollResizePositioning && !isOverflowYHidden;
|
|
// If there is a finalHeight given then we assume that the user knows and will handle
|
|
// additional positioning adjustments so we should call positionCard
|
|
var newPositions = finalHeight
|
|
? (0, Positioning_1.positionCard)(currentProps, hostElement.current, dupeCalloutElement, previousPositions, win)
|
|
: (0, Positioning_1.positionCallout)(currentProps, hostElement.current, dupeCalloutElement, previousPositions, shouldScroll, undefined, win);
|
|
// clean up duplicate calloutElement
|
|
(_b = calloutElement.parentElement) === null || _b === void 0 ? void 0 : _b.removeChild(dupeCalloutElement);
|
|
// Set the new position only when the positions do not exist or one of the new callout positions
|
|
// is different. The position should not change if the position is within 2 decimal places.
|
|
if ((!positions && newPositions) ||
|
|
(positions && newPositions && !arePositionsEqual(positions, newPositions) && positionAttempts.current < 5)) {
|
|
// We should not reposition the callout more than a few times, if it is then the content is likely resizing
|
|
// and we should stop trying to reposition to prevent a stack overflow.
|
|
positionAttempts.current++;
|
|
setPositions(newPositions);
|
|
}
|
|
else if (positionAttempts.current > 0) {
|
|
// Only call the onPositioned callback if the callout has been re-positioned at least once.
|
|
positionAttempts.current = 0;
|
|
onPositioned === null || onPositioned === void 0 ? void 0 : onPositioned(positions);
|
|
}
|
|
}
|
|
}, calloutElement);
|
|
previousTarget.current = target;
|
|
return function () {
|
|
async.cancelAnimationFrame(timerId_1);
|
|
previousTarget.current = undefined;
|
|
};
|
|
}
|
|
else {
|
|
// When the callout is hidden, clear position state so that it is not accidentally used next render.
|
|
setPositions(undefined);
|
|
positionAttempts.current = 0;
|
|
}
|
|
}, [
|
|
hidden,
|
|
directionalHint,
|
|
async,
|
|
calloutElement,
|
|
calloutMaxHeight,
|
|
hostElement,
|
|
targetRef,
|
|
finalHeight,
|
|
getBounds,
|
|
onPositioned,
|
|
positions,
|
|
props,
|
|
target,
|
|
hideOverflow,
|
|
preferScrollResizePositioning,
|
|
popupOverflowY,
|
|
win,
|
|
]);
|
|
return positions;
|
|
}
|
|
/**
|
|
* (Hook) to set up behavior to automatically focus the callout when it appears, if indicated by props.
|
|
*/
|
|
function useAutoFocus(_a, positions, calloutElement) {
|
|
var hidden = _a.hidden, setInitialFocus = _a.setInitialFocus;
|
|
var async = (0, react_hooks_1.useAsync)();
|
|
var hasPositions = !!positions;
|
|
React.useEffect(function () {
|
|
if (!hidden && setInitialFocus && hasPositions && calloutElement) {
|
|
var timerId_2 = async.requestAnimationFrame(function () { return (0, Utilities_1.focusFirstChild)(calloutElement); }, calloutElement);
|
|
return function () { return async.cancelAnimationFrame(timerId_2); };
|
|
}
|
|
}, [hidden, hasPositions, async, calloutElement, setInitialFocus]);
|
|
}
|
|
/**
|
|
* (Hook) to set up various handlers to dismiss the popup when it loses focus or the window scrolls or similar cases.
|
|
*/
|
|
function useDismissHandlers(_a, positions, hostElement, targetRef, targetWindow) {
|
|
var hidden = _a.hidden, onDismiss = _a.onDismiss, preventDismissOnScroll = _a.preventDismissOnScroll, preventDismissOnResize = _a.preventDismissOnResize, preventDismissOnLostFocus = _a.preventDismissOnLostFocus, dismissOnTargetClick = _a.dismissOnTargetClick, shouldDismissOnWindowFocus = _a.shouldDismissOnWindowFocus, preventDismissOnEvent = _a.preventDismissOnEvent;
|
|
var isMouseDownOnPopup = React.useRef(false);
|
|
var async = (0, react_hooks_1.useAsync)();
|
|
var mouseDownHandlers = (0, react_hooks_1.useConst)([
|
|
function () {
|
|
isMouseDownOnPopup.current = true;
|
|
},
|
|
function () {
|
|
isMouseDownOnPopup.current = false;
|
|
},
|
|
]);
|
|
var positionsExists = !!positions;
|
|
React.useEffect(function () {
|
|
var dismissOnScroll = function (ev) {
|
|
if (positionsExists && !preventDismissOnScroll) {
|
|
dismissOnClickOrScroll(ev);
|
|
}
|
|
};
|
|
var dismissOnResize = function (ev) {
|
|
if (!preventDismissOnResize && !(preventDismissOnEvent && preventDismissOnEvent(ev))) {
|
|
onDismiss === null || onDismiss === void 0 ? void 0 : onDismiss(ev);
|
|
}
|
|
};
|
|
var dismissOnLostFocus = function (ev) {
|
|
if (!preventDismissOnLostFocus) {
|
|
dismissOnClickOrScroll(ev);
|
|
}
|
|
};
|
|
var dismissOnClickOrScroll = function (ev) {
|
|
var eventPaths = ev.composedPath ? ev.composedPath() : [];
|
|
var target = eventPaths.length > 0 ? eventPaths[0] : ev.target;
|
|
var isEventTargetOutsideCallout = hostElement.current && !(0, Utilities_1.elementContains)(hostElement.current, target);
|
|
// If mouse is pressed down on callout but moved outside then released, don't dismiss the callout.
|
|
if (isEventTargetOutsideCallout && isMouseDownOnPopup.current) {
|
|
isMouseDownOnPopup.current = false;
|
|
return;
|
|
}
|
|
if ((!targetRef.current && isEventTargetOutsideCallout) ||
|
|
(ev.target !== targetWindow &&
|
|
isEventTargetOutsideCallout &&
|
|
(!targetRef.current ||
|
|
'stopPropagation' in targetRef.current ||
|
|
dismissOnTargetClick ||
|
|
(target !== targetRef.current && !(0, Utilities_1.elementContains)(targetRef.current, target))))) {
|
|
if (preventDismissOnEvent && preventDismissOnEvent(ev)) {
|
|
return;
|
|
}
|
|
onDismiss === null || onDismiss === void 0 ? void 0 : onDismiss(ev);
|
|
}
|
|
};
|
|
var dismissOnTargetWindowBlur = function (ev) {
|
|
// Do nothing
|
|
if (!shouldDismissOnWindowFocus) {
|
|
return;
|
|
}
|
|
if (((preventDismissOnEvent && !preventDismissOnEvent(ev)) ||
|
|
(!preventDismissOnEvent && !preventDismissOnLostFocus)) &&
|
|
!(targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.document.hasFocus()) &&
|
|
ev.relatedTarget === null) {
|
|
onDismiss === null || onDismiss === void 0 ? void 0 : onDismiss(ev);
|
|
}
|
|
};
|
|
// This is added so the callout will dismiss when the window is scrolled
|
|
// but not when something inside the callout is scrolled. The delay seems
|
|
// to be required to avoid React firing an async focus event in IE from
|
|
// the target changing focus quickly prior to rendering the callout.
|
|
var disposablesPromise = new Promise(function (resolve) {
|
|
async.setTimeout(function () {
|
|
if (!hidden && targetWindow) {
|
|
var disposables_1 = [
|
|
(0, Utilities_1.on)(targetWindow, 'scroll', dismissOnScroll, true),
|
|
(0, Utilities_1.on)(targetWindow, 'resize', dismissOnResize, true),
|
|
(0, Utilities_1.on)(targetWindow.document.documentElement, 'focus', dismissOnLostFocus, true),
|
|
(0, Utilities_1.on)(targetWindow.document.documentElement, 'click', dismissOnLostFocus, true),
|
|
(0, Utilities_1.on)(targetWindow, 'blur', dismissOnTargetWindowBlur, true),
|
|
];
|
|
resolve(function () {
|
|
disposables_1.forEach(function (dispose) { return dispose(); });
|
|
});
|
|
}
|
|
}, 0);
|
|
});
|
|
return function () {
|
|
disposablesPromise.then(function (dispose) { return dispose(); });
|
|
};
|
|
}, [
|
|
hidden,
|
|
async,
|
|
hostElement,
|
|
targetRef,
|
|
targetWindow,
|
|
onDismiss,
|
|
shouldDismissOnWindowFocus,
|
|
dismissOnTargetClick,
|
|
preventDismissOnLostFocus,
|
|
preventDismissOnResize,
|
|
preventDismissOnScroll,
|
|
positionsExists,
|
|
preventDismissOnEvent,
|
|
]);
|
|
return mouseDownHandlers;
|
|
}
|
|
exports.CalloutContentBase = React.memo(React.forwardRef(function (propsWithoutDefaults, forwardedRef) {
|
|
var props = (0, Utilities_1.getPropsWithDefaults)(DEFAULT_PROPS, propsWithoutDefaults);
|
|
var styles = props.styles, style = props.style, ariaLabel = props.ariaLabel, ariaDescribedBy = props.ariaDescribedBy, ariaLabelledBy = props.ariaLabelledBy, className = props.className, isBeakVisible = props.isBeakVisible, children = props.children, beakWidth = props.beakWidth, calloutWidth = props.calloutWidth, calloutMaxWidth = props.calloutMaxWidth, calloutMinWidth = props.calloutMinWidth, doNotLayer = props.doNotLayer, finalHeight = props.finalHeight, _a = props.hideOverflow, hideOverflow = _a === void 0 ? !!finalHeight : _a, backgroundColor = props.backgroundColor, calloutMaxHeight = props.calloutMaxHeight, onScroll = props.onScroll,
|
|
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
_b = props.shouldRestoreFocus,
|
|
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
shouldRestoreFocus = _b === void 0 ? true : _b, target = props.target, hidden = props.hidden, onLayerMounted = props.onLayerMounted, popupProps = props.popupProps;
|
|
var hostElement = React.useRef(null);
|
|
var popupRef = React.useRef(null);
|
|
var mergedPopupRefs = (0, react_hooks_1.useMergedRefs)(popupRef, popupProps === null || popupProps === void 0 ? void 0 : popupProps.ref);
|
|
var _c = React.useState(null), calloutElement = _c[0], setCalloutElement = _c[1];
|
|
var calloutCallback = React.useCallback(function (calloutEl) {
|
|
setCalloutElement(calloutEl);
|
|
}, []);
|
|
var rootRef = (0, react_hooks_1.useMergedRefs)(hostElement, forwardedRef);
|
|
var _d = (0, react_hooks_1.useTarget)(props.target, {
|
|
current: calloutElement,
|
|
}), targetRef = _d[0], targetWindow = _d[1];
|
|
var getBounds = useBounds(props, targetRef, targetWindow);
|
|
var positions = usePositions(props, hostElement, calloutElement, targetRef, getBounds, mergedPopupRefs);
|
|
var maxHeight = useMaxHeight(props, getBounds, targetRef, positions);
|
|
var _e = useDismissHandlers(props, positions, hostElement, targetRef, targetWindow), mouseDownOnPopup = _e[0], mouseUpOnPopup = _e[1];
|
|
// do not set both top and bottom css props from positions
|
|
// instead, use maxHeight
|
|
var isForcedInBounds = (positions === null || positions === void 0 ? void 0 : positions.elementPosition.top) && (positions === null || positions === void 0 ? void 0 : positions.elementPosition.bottom);
|
|
var cssPositions = tslib_1.__assign(tslib_1.__assign({}, positions === null || positions === void 0 ? void 0 : positions.elementPosition), { maxHeight: maxHeight });
|
|
if (isForcedInBounds) {
|
|
cssPositions.bottom = undefined;
|
|
}
|
|
useAutoFocus(props, positions, calloutElement);
|
|
React.useEffect(function () {
|
|
if (!hidden) {
|
|
onLayerMounted === null || onLayerMounted === void 0 ? void 0 : onLayerMounted();
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- should only run if hidden changes
|
|
}, [hidden]);
|
|
// If there is no target window then we are likely in server side rendering and we should not render anything.
|
|
if (!targetWindow) {
|
|
return null;
|
|
}
|
|
var overflowYHidden = hideOverflow;
|
|
var beakVisible = isBeakVisible && !!target;
|
|
var classNames = getClassNames(styles, {
|
|
theme: props.theme,
|
|
className: className,
|
|
overflowYHidden: overflowYHidden,
|
|
calloutWidth: calloutWidth,
|
|
positions: positions,
|
|
beakWidth: beakWidth,
|
|
backgroundColor: backgroundColor,
|
|
calloutMaxWidth: calloutMaxWidth,
|
|
calloutMinWidth: calloutMinWidth,
|
|
doNotLayer: doNotLayer,
|
|
});
|
|
var overflowStyle = tslib_1.__assign(tslib_1.__assign({ maxHeight: calloutMaxHeight ? calloutMaxHeight : '100%' }, style), (overflowYHidden && { overflowY: 'hidden' }));
|
|
var visibilityStyle = props.hidden ? { visibility: 'hidden' } : undefined;
|
|
// React.CSSProperties does not understand IRawStyle, so the inline animations will need to be cast as any for now.
|
|
return (React.createElement("div", { ref: rootRef, className: classNames.container, style: visibilityStyle },
|
|
React.createElement("div", tslib_1.__assign({}, (0, Utilities_1.getNativeProps)(props, Utilities_1.divProperties, ARIA_ROLE_ATTRIBUTES), { className: (0, Utilities_1.css)(classNames.root, positions && positions.targetEdge && ANIMATIONS[positions.targetEdge]), style: positions ? tslib_1.__assign({}, cssPositions) : OFF_SCREEN_STYLE,
|
|
// Safari and Firefox on Mac OS requires this to back-stop click events so focus remains in the Callout.
|
|
// See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
|
|
tabIndex: -1, ref: calloutCallback }),
|
|
beakVisible && React.createElement("div", { className: classNames.beak, style: getBeakPosition(positions) }),
|
|
beakVisible && React.createElement("div", { className: classNames.beakCurtain }),
|
|
React.createElement(Popup_1.Popup
|
|
// don't use getNativeElementProps for role and roledescription because it will also
|
|
// pass through data-* props (resulting in them being used in two places)
|
|
, tslib_1.__assign({
|
|
// don't use getNativeElementProps for role and roledescription because it will also
|
|
// pass through data-* props (resulting in them being used in two places)
|
|
role: props.role, "aria-roledescription": props['aria-roledescription'], ariaDescribedBy: ariaDescribedBy, ariaLabel: ariaLabel, ariaLabelledBy: ariaLabelledBy, className: classNames.calloutMain, onDismiss: props.onDismiss, onMouseDown: mouseDownOnPopup, onMouseUp: mouseUpOnPopup, onRestoreFocus: props.onRestoreFocus, onScroll: onScroll,
|
|
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
shouldRestoreFocus: shouldRestoreFocus, style: overflowStyle }, popupProps, { ref: mergedPopupRefs }), children))));
|
|
}), function (previousProps, nextProps) {
|
|
if (!nextProps.shouldUpdateWhenHidden && previousProps.hidden && nextProps.hidden) {
|
|
// Do not update when hidden.
|
|
return true;
|
|
}
|
|
return (0, Utilities_1.shallowCompare)(previousProps, nextProps);
|
|
});
|
|
/**
|
|
* (Utility) to find and return the current `Callout` Beak position.
|
|
*
|
|
* @param positions
|
|
*/
|
|
function getBeakPosition(positions) {
|
|
var _a, _b;
|
|
var beakPositionStyle = tslib_1.__assign(tslib_1.__assign({}, (_a = positions === null || positions === void 0 ? void 0 : positions.beakPosition) === null || _a === void 0 ? void 0 : _a.elementPosition), { display: ((_b = positions === null || positions === void 0 ? void 0 : positions.beakPosition) === null || _b === void 0 ? void 0 : _b.hideBeak) ? 'none' : undefined });
|
|
if (!beakPositionStyle.top && !beakPositionStyle.bottom && !beakPositionStyle.left && !beakPositionStyle.right) {
|
|
beakPositionStyle.left = BEAK_ORIGIN_POSITION.left;
|
|
beakPositionStyle.top = BEAK_ORIGIN_POSITION.top;
|
|
}
|
|
return beakPositionStyle;
|
|
}
|
|
/**
|
|
* (Utility) used to compare two different elementPositions to determine whether they are equal.
|
|
*
|
|
* @param prevElementPositions
|
|
* @param newElementPosition
|
|
*/
|
|
function arePositionsEqual(prevElementPositions, newElementPosition) {
|
|
return (comparePositions(prevElementPositions.elementPosition, newElementPosition.elementPosition) &&
|
|
comparePositions(prevElementPositions.beakPosition.elementPosition, newElementPosition.beakPosition.elementPosition));
|
|
}
|
|
/**
|
|
* (Utility) used in **arePositionsEqual** to compare two different elementPositions.
|
|
*
|
|
* @param prevElementPositions
|
|
* @param newElementPositions
|
|
*/
|
|
function comparePositions(prevElementPositions, newElementPositions) {
|
|
for (var key in newElementPositions) {
|
|
if (newElementPositions.hasOwnProperty(key)) {
|
|
var oldPositionEdge = prevElementPositions[key];
|
|
var newPositionEdge = newElementPositions[key];
|
|
if (oldPositionEdge !== undefined && newPositionEdge !== undefined) {
|
|
if (oldPositionEdge.toFixed(2) !== newPositionEdge.toFixed(2)) {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
exports.CalloutContentBase.displayName = COMPONENT_NAME;
|
|
});
|
|
//# sourceMappingURL=CalloutContent.base.js.map
|