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,11 @@
import * as React from 'react';
import { Target } from '@fluentui/react-hooks';
import type { IContextualMenuProps, IContextualMenuItem } from './ContextualMenu.types';
export declare function getSubmenuItems(item: IContextualMenuItem, options?: {
target?: Target;
}): IContextualMenuItem[] | undefined;
/**
* Returns true if a list of menu items can contain a checkbox
*/
export declare function canAnyMenuItemsCheck(items: IContextualMenuItem[]): boolean;
export declare const ContextualMenuBase: React.FunctionComponent<IContextualMenuProps>;
@@ -0,0 +1,935 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuBase = void 0;
exports.getSubmenuItems = getSubmenuItems;
exports.canAnyMenuItemsCheck = canAnyMenuItemsCheck;
var tslib_1 = require("tslib");
var React = require("react");
var ContextualMenu_types_1 = require("./ContextualMenu.types");
var DirectionalHint_1 = require("../../common/DirectionalHint");
var FocusZone_1 = require("../../FocusZone");
var Utilities_1 = require("../../Utilities");
var index_1 = require("../../utilities/contextualMenu/index");
var Callout_1 = require("../../Callout");
var ContextualMenuItem_1 = require("./ContextualMenuItem");
var index_2 = require("./ContextualMenuItemWrapper/index");
var Styling_1 = require("../../Styling");
var ContextualMenu_classNames_1 = require("./ContextualMenu.classNames");
var react_hooks_1 = require("@fluentui/react-hooks");
var ResponsiveMode_1 = require("../../ResponsiveMode");
var index_3 = require("../../utilities/MenuContext/index");
var getClassNames = (0, Utilities_1.classNamesFunction)();
var getContextualMenuItemClassNames = (0, Utilities_1.classNamesFunction)();
// The default ContextualMenu properties have no items and beak, the default submenu direction is right and top.
var DEFAULT_PROPS = {
items: [],
shouldFocusOnMount: true,
gapSpace: 0,
directionalHint: DirectionalHint_1.DirectionalHint.bottomAutoEdge,
beakWidth: 16,
};
/* return number of menu items, excluding headers and dividers */
function getItemCount(items) {
var totalItemCount = 0;
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
var item = items_1[_i];
if (item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Divider && item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Header) {
var itemCount = item.customOnRenderListLength ? item.customOnRenderListLength : 1;
totalItemCount += itemCount;
}
}
return totalItemCount;
}
function getSubmenuItems(item, options) {
var target = options === null || options === void 0 ? void 0 : options.target;
// eslint-disable-next-line @typescript-eslint/no-deprecated
var items = item.subMenuProps ? item.subMenuProps.items : item.items;
if (items) {
var overrideItems = [];
for (var _i = 0, items_2 = items; _i < items_2.length; _i++) {
var subItem = items_2[_i];
if (subItem.preferMenuTargetAsEventTarget) {
// For sub-items which need an overridden target, intercept `onClick`
var onClick = subItem.onClick, contextItem = tslib_1.__rest(subItem, ["onClick"]);
overrideItems.push(tslib_1.__assign(tslib_1.__assign({}, contextItem), { onClick: getOnClickWithOverrideTarget(onClick, target) }));
}
else {
overrideItems.push(subItem);
}
}
return overrideItems;
}
}
/**
* Returns true if a list of menu items can contain a checkbox
*/
function canAnyMenuItemsCheck(items) {
return items.some(function (item) {
if (item.canCheck) {
return true;
}
// If the item is a section, check if any of the items in the section can check.
if (item.sectionProps && item.sectionProps.items.some(function (submenuItem) { return submenuItem.canCheck === true; })) {
return true;
}
return false;
});
}
var NavigationIdleDelay = 250; /* ms */
var COMPONENT_NAME = 'ContextualMenu';
var _getMenuItemStylesFunction = (0, Utilities_1.memoizeFunction)(function () {
var styles = [];
for (var _i = 0; _i < arguments.length; _i++) {
styles[_i] = arguments[_i];
}
return function (styleProps) {
return Styling_1.concatStyleSetsWithProps.apply(void 0, tslib_1.__spreadArray([styleProps, ContextualMenu_classNames_1.getItemStyles], styles, false));
};
});
//#region Custom hooks
function useVisibility(props, targetWindow) {
var _a = props.hidden, hidden = _a === void 0 ? false : _a, onMenuDismissed = props.onMenuDismissed, onMenuOpened = props.onMenuOpened;
var previousHidden = (0, react_hooks_1.usePrevious)(hidden);
var onMenuOpenedRef = React.useRef(onMenuOpened);
var onMenuClosedRef = React.useRef(onMenuDismissed);
var propsRef = React.useRef(props);
onMenuOpenedRef.current = onMenuOpened;
onMenuClosedRef.current = onMenuDismissed;
propsRef.current = props;
React.useEffect(function () {
var _a, _b;
// Don't issue dismissed callbacks on initial mount
if (hidden && previousHidden === false) {
(_a = onMenuClosedRef.current) === null || _a === void 0 ? void 0 : _a.call(onMenuClosedRef, propsRef.current);
}
else if (!hidden && previousHidden !== false) {
(_b = onMenuOpenedRef.current) === null || _b === void 0 ? void 0 : _b.call(onMenuOpenedRef, propsRef.current);
}
}, [hidden, previousHidden]);
// Issue onDismissedCallback on unmount
React.useEffect(function () { return function () { var _a; return (_a = onMenuClosedRef.current) === null || _a === void 0 ? void 0 : _a.call(onMenuClosedRef, propsRef.current); }; }, []);
}
function useSubMenuState(_a, dismiss) {
var hidden = _a.hidden, items = _a.items, theme = _a.theme, className = _a.className, id = _a.id, menuTarget = _a.target;
var _b = React.useState(), expandedMenuItemKey = _b[0], setExpandedMenuItemKey = _b[1];
var _c = React.useState(), submenuTarget = _c[0], setSubmenuTarget = _c[1];
/** True if the menu was expanded by mouse click OR hover (as opposed to by keyboard) */
var _d = React.useState(), shouldFocusOnContainer = _d[0], setShouldFocusOnContainer = _d[1];
var subMenuId = (0, react_hooks_1.useId)(COMPONENT_NAME, id);
var closeSubMenu = React.useCallback(function () {
setShouldFocusOnContainer(undefined);
setExpandedMenuItemKey(undefined);
setSubmenuTarget(undefined);
}, []);
var openSubMenu = React.useCallback(function (_a, target, focusContainer) {
var submenuItemKey = _a.key;
if (expandedMenuItemKey === submenuItemKey) {
return;
}
target.focus();
setShouldFocusOnContainer(focusContainer);
setExpandedMenuItemKey(submenuItemKey);
setSubmenuTarget(target);
}, [expandedMenuItemKey]);
React.useEffect(function () {
if (hidden) {
closeSubMenu();
}
}, [hidden, closeSubMenu]);
var onSubMenuDismiss = useOnSubmenuDismiss(dismiss, closeSubMenu);
var getSubmenuProps = function () {
var item = findItemByKeyFromItems(expandedMenuItemKey, items);
var submenuProps = null;
if (item) {
submenuProps = {
items: getSubmenuItems(item, { target: menuTarget }),
target: submenuTarget,
onDismiss: onSubMenuDismiss,
isSubMenu: true,
id: subMenuId,
shouldFocusOnMount: true,
shouldFocusOnContainer: shouldFocusOnContainer,
directionalHint: (0, Utilities_1.getRTL)(theme) ? DirectionalHint_1.DirectionalHint.leftTopEdge : DirectionalHint_1.DirectionalHint.rightTopEdge,
className: className,
gapSpace: 0,
isBeakVisible: false,
};
if (item.subMenuProps) {
(0, Utilities_1.assign)(submenuProps, item.subMenuProps);
}
if (item.preferMenuTargetAsEventTarget) {
var onItemClick = item.onItemClick;
submenuProps.onItemClick = getOnClickWithOverrideTarget(onItemClick, menuTarget);
}
}
return submenuProps;
};
return [expandedMenuItemKey, openSubMenu, getSubmenuProps, onSubMenuDismiss];
}
function useShouldUpdateFocusOnMouseMove(_a) {
var delayUpdateFocusOnHover = _a.delayUpdateFocusOnHover, hidden = _a.hidden;
var shouldUpdateFocusOnMouseEvent = React.useRef(!delayUpdateFocusOnHover);
var gotMouseMove = React.useRef(false);
React.useEffect(function () {
shouldUpdateFocusOnMouseEvent.current = !delayUpdateFocusOnHover;
gotMouseMove.current = hidden ? false : !delayUpdateFocusOnHover && gotMouseMove.current;
}, [delayUpdateFocusOnHover, hidden]);
var onMenuFocusCapture = React.useCallback(function () {
if (delayUpdateFocusOnHover) {
shouldUpdateFocusOnMouseEvent.current = false;
}
}, [delayUpdateFocusOnHover]);
return [shouldUpdateFocusOnMouseEvent, gotMouseMove, onMenuFocusCapture];
}
function usePreviousActiveElement(_a, targetWindow, hostElement) {
var hidden = _a.hidden, onRestoreFocus = _a.onRestoreFocus;
var previousActiveElement = React.useRef(undefined);
var tryFocusPreviousActiveElement = React.useCallback(function (options) {
var _a, _b;
if (onRestoreFocus) {
onRestoreFocus(options);
}
else if (options === null || options === void 0 ? void 0 : options.documentContainsFocus) {
// Make sure that the focus method actually exists
// In some cases the object might exist but not be a real element.
// This is primarily for IE 11 and should be removed once IE 11 is no longer in use.
(_b = (_a = previousActiveElement.current) === null || _a === void 0 ? void 0 : _a.focus) === null || _b === void 0 ? void 0 : _b.call(_a);
}
}, [onRestoreFocus]);
(0, react_hooks_1.useIsomorphicLayoutEffect)(function () {
var _a, _b;
if (!hidden) {
var newElement = targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.document.activeElement;
if (!((_a = hostElement.current) === null || _a === void 0 ? void 0 : _a.contains(newElement)) && newElement.tagName !== 'BODY') {
previousActiveElement.current = newElement;
}
}
else if (previousActiveElement.current) {
tryFocusPreviousActiveElement({
originalElement: previousActiveElement.current,
containsFocus: true,
documentContainsFocus: ((_b = (0, Utilities_1.getDocument)()) === null || _b === void 0 ? void 0 : _b.hasFocus()) || false,
});
previousActiveElement.current = undefined;
}
}, [hidden, targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.document.activeElement, tryFocusPreviousActiveElement, hostElement]);
return [tryFocusPreviousActiveElement];
}
function useKeyHandlers(_a, dismiss, hostElement, openSubMenu) {
var theme = _a.theme, isSubMenu = _a.isSubMenu, _b = _a.focusZoneProps, _c = _b === void 0 ? {} : _b, checkForNoWrap = _c.checkForNoWrap, _d = _c.direction, focusZoneDirection = _d === void 0 ? FocusZone_1.FocusZoneDirection.vertical : _d;
/** True if the most recent keydown event was for alt (option) or meta (command). */
var lastKeyDownWasAltOrMeta = React.useRef(undefined);
/**
* Calls `shouldHandleKey` to determine whether the keyboard event should be handled;
* if so, stops event propagation and dismisses menu(s).
* @param ev - The keyboard event.
* @param shouldHandleKey - Returns whether we should handle this keyboard event.
* @param dismissAllMenus - If true, dismiss all menus. Otherwise, dismiss only the current menu.
* Only does anything if `shouldHandleKey` returns true.
* @returns Whether the event was handled.
*/
var keyHandler = function (ev, shouldHandleKey, dismissAllMenus) {
var handled = false;
if (shouldHandleKey(ev)) {
dismiss(ev, dismissAllMenus);
ev.preventDefault();
ev.stopPropagation();
handled = true;
}
return handled;
};
/**
* Checks if the submenu should be closed
*/
var shouldCloseSubMenu = function (ev) {
var submenuCloseKey = (0, Utilities_1.getRTL)(theme) ? Utilities_1.KeyCodes.right : Utilities_1.KeyCodes.left;
// eslint-disable-next-line @typescript-eslint/no-deprecated
if (ev.which !== submenuCloseKey || !isSubMenu) {
return false;
}
return !!(focusZoneDirection === FocusZone_1.FocusZoneDirection.vertical ||
(checkForNoWrap && !(0, Utilities_1.shouldWrapFocus)(ev.target, 'data-no-horizontal-wrap')));
};
var shouldHandleKeyDown = function (ev) {
return (
// eslint-disable-next-line @typescript-eslint/no-deprecated
ev.which === Utilities_1.KeyCodes.escape || shouldCloseSubMenu(ev) || (ev.which === Utilities_1.KeyCodes.up && (ev.altKey || ev.metaKey)));
};
var onKeyDown = function (ev) {
// Take note if we are processing an alt (option) or meta (command) keydown.
// See comment in shouldHandleKeyUp for reasoning.
lastKeyDownWasAltOrMeta.current = isAltOrMeta(ev);
// On Mac, pressing escape dismisses all levels of native context menus
// eslint-disable-next-line @typescript-eslint/no-deprecated
var dismissAllMenus = ev.which === Utilities_1.KeyCodes.escape && ((0, Utilities_1.isMac)() || (0, Utilities_1.isIOS)());
return keyHandler(ev, shouldHandleKeyDown, dismissAllMenus);
};
/**
* We close the menu on key up only if ALL of the following are true:
* - Most recent key down was alt or meta (command)
* - The alt/meta key down was NOT followed by some other key (such as down/up arrow to
* expand/collapse the menu)
* - We're not on a Mac (or iOS)
*
* This is because on Windows, pressing alt moves focus to the application menu bar or similar,
* closing any open context menus. There is not a similar behavior on Macs.
*/
var shouldHandleKeyUp = function (ev) {
var keyPressIsAltOrMetaAlone = lastKeyDownWasAltOrMeta.current && isAltOrMeta(ev);
lastKeyDownWasAltOrMeta.current = false;
return !!keyPressIsAltOrMetaAlone && !((0, Utilities_1.isIOS)() || (0, Utilities_1.isMac)());
};
var onKeyUp = function (ev) {
return keyHandler(ev, shouldHandleKeyUp, true /* dismissAllMenus */);
};
var onMenuKeyDown = function (ev) {
// Mark as handled if onKeyDown returns true (for handling collapse cases)
// or if we are attempting to expand a submenu
var handled = onKeyDown(ev);
if (handled || !hostElement.current) {
return;
}
// If we have a modifier key being pressed, we do not want to move focus.
// Otherwise, handle up and down keys.
var hasModifier = !!(ev.altKey || ev.metaKey);
// eslint-disable-next-line @typescript-eslint/no-deprecated
var isUp = ev.which === Utilities_1.KeyCodes.up;
// eslint-disable-next-line @typescript-eslint/no-deprecated
var isDown = ev.which === Utilities_1.KeyCodes.down;
if (!hasModifier && (isUp || isDown)) {
var elementToFocus = isUp
? (0, Utilities_1.getLastFocusable)(hostElement.current, hostElement.current.lastChild, true)
: (0, Utilities_1.getFirstFocusable)(hostElement.current, hostElement.current.firstChild, true);
if (elementToFocus) {
elementToFocus.focus();
ev.preventDefault();
ev.stopPropagation();
}
}
};
var onItemKeyDown = function (item, ev) {
var openKey = (0, Utilities_1.getRTL)(theme) ? Utilities_1.KeyCodes.left : Utilities_1.KeyCodes.right;
if (!item.disabled &&
// eslint-disable-next-line @typescript-eslint/no-deprecated
(ev.which === openKey || ev.which === Utilities_1.KeyCodes.enter || (ev.which === Utilities_1.KeyCodes.down && (ev.altKey || ev.metaKey)))) {
openSubMenu(item, ev.currentTarget);
ev.preventDefault();
}
};
return [onKeyDown, onKeyUp, onMenuKeyDown, onItemKeyDown];
}
function useScrollHandler(asyncTracker) {
var isScrollIdle = React.useRef(true);
var scrollIdleTimeoutId = React.useRef(undefined);
/**
* Scroll handler for the callout to make sure the mouse events
* for updating focus are not interacting during scroll
*/
var onScroll = function () {
if (!isScrollIdle.current && scrollIdleTimeoutId.current !== undefined) {
asyncTracker.clearTimeout(scrollIdleTimeoutId.current);
scrollIdleTimeoutId.current = undefined;
}
else {
isScrollIdle.current = false;
}
scrollIdleTimeoutId.current = asyncTracker.setTimeout(function () {
isScrollIdle.current = true;
}, NavigationIdleDelay);
};
return [onScroll, isScrollIdle];
}
function useOnSubmenuDismiss(dismiss, closeSubMenu) {
var isMountedRef = React.useRef(false);
React.useEffect(function () {
isMountedRef.current = true;
return function () {
isMountedRef.current = false;
};
}, []);
/**
* This function is called ASYNCHRONOUSLY, and so there is a chance it is called
* after the component is unmounted. The isMountedRef is added to prevent
* from calling setState() after unmount. Do NOT copy this pattern in synchronous
* code.
*/
var onSubMenuDismiss = function (ev, dismissAll) {
if (dismissAll) {
dismiss(ev, dismissAll);
}
else if (isMountedRef.current) {
closeSubMenu();
}
};
return onSubMenuDismiss;
}
function useSubmenuEnterTimer(_a, asyncTracker) {
var _b = _a.subMenuHoverDelay, subMenuHoverDelay = _b === void 0 ? NavigationIdleDelay : _b;
var enterTimerRef = React.useRef(undefined);
var cancelSubMenuTimer = function () {
if (enterTimerRef.current !== undefined) {
asyncTracker.clearTimeout(enterTimerRef.current);
enterTimerRef.current = undefined;
}
};
var startSubmenuTimer = function (onTimerExpired) {
enterTimerRef.current = asyncTracker.setTimeout(function () {
onTimerExpired();
cancelSubMenuTimer();
}, subMenuHoverDelay);
};
return [cancelSubMenuTimer, startSubmenuTimer, enterTimerRef];
}
function useMouseHandlers(props,
// eslint-disable-next-line @typescript-eslint/no-deprecated
isScrollIdle, subMenuEntryTimer, targetWindow,
// eslint-disable-next-line @typescript-eslint/no-deprecated
shouldUpdateFocusOnMouseEvent,
// eslint-disable-next-line @typescript-eslint/no-deprecated
gotMouseMove, expandedMenuItemKey, hostElement, startSubmenuTimer, cancelSubMenuTimer, openSubMenu, onSubMenuDismiss, dismiss) {
var menuTarget = props.target;
var onItemMouseEnterBase = function (item, ev, target) {
if (shouldUpdateFocusOnMouseEvent.current) {
gotMouseMove.current = true;
}
if (shouldIgnoreMouseEvent()) {
return;
}
updateFocusOnMouseEvent(item, ev, target);
};
var onItemMouseMoveBase = function (item, ev, target) {
var targetElement = ev.currentTarget;
// Always do this check to make sure we record a mouseMove if needed (even if we are timed out)
if (shouldUpdateFocusOnMouseEvent.current) {
gotMouseMove.current = true;
}
else {
return;
}
if (!isScrollIdle.current ||
subMenuEntryTimer.current !== undefined ||
targetElement === (targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.document.activeElement)) {
return;
}
updateFocusOnMouseEvent(item, ev, target);
};
var shouldIgnoreMouseEvent = function () {
return !isScrollIdle.current || !gotMouseMove.current;
};
var onMouseItemLeave = function (item, ev) {
var _a;
if (shouldIgnoreMouseEvent()) {
return;
}
cancelSubMenuTimer();
if (expandedMenuItemKey !== undefined) {
return;
}
/**
* IE11 focus() method forces parents to scroll to top of element.
* Edge and IE expose a setActive() function for focusable divs that
* sets the page focus but does not scroll the parent element.
*/
if (hostElement.current.setActive) {
try {
hostElement.current.setActive();
}
catch (e) {
/* no-op */
}
}
else {
(_a = hostElement.current) === null || _a === void 0 ? void 0 : _a.focus();
}
};
/**
* Handles updating focus when mouseEnter or mouseMove fire.
* As part of updating focus, This function will also update
* the expand/collapse state accordingly.
*/
var updateFocusOnMouseEvent = function (item, ev, target) {
var targetElement = target ? target : ev.currentTarget;
if (item.key === expandedMenuItemKey) {
return;
}
cancelSubMenuTimer();
// If the menu is not expanded we can update focus without any delay
if (expandedMenuItemKey === undefined) {
targetElement.focus();
}
// Delay updating expanding/dismissing the submenu
// and only set focus if we have not already done so
if ((0, index_1.hasSubmenu)(item)) {
ev.stopPropagation();
startSubmenuTimer(function () {
targetElement.focus();
openSubMenu(item, targetElement, true);
});
}
else {
startSubmenuTimer(function () {
onSubMenuDismiss(ev);
targetElement.focus();
});
}
};
var onItemClick = function (item, ev) {
onItemClickBase(item, ev, ev.currentTarget);
};
var onItemClickBase = function (item, ev, target) {
var items = getSubmenuItems(item, { target: menuTarget });
// Cancel an async menu item hover timeout action from being taken and instead
// just trigger the click event instead.
cancelSubMenuTimer();
if (!(0, index_1.hasSubmenu)(item) && (!items || !items.length)) {
// This is an item without a menu. Click it.
executeItemClick(item, ev);
}
else {
if (item.key !== expandedMenuItemKey) {
// This has a collapsed sub menu. Expand it.
// focus on the container by default when the menu is opened with a click event
// this differentiates from a keyboard interaction triggering the click event
var shouldFocusOnContainer = typeof props.shouldFocusOnContainer === 'boolean'
? props.shouldFocusOnContainer
: ev.nativeEvent.pointerType === 'mouse';
openSubMenu(item, target, shouldFocusOnContainer);
}
}
ev.stopPropagation();
ev.preventDefault();
};
var onAnchorClick = function (item, ev) {
executeItemClick(item, ev);
ev.stopPropagation();
};
var executeItemClick = function (item, ev) {
if (item.disabled || item.isDisabled) {
return;
}
if (item.preferMenuTargetAsEventTarget) {
overrideTarget(ev, menuTarget);
}
var shouldDismiss = false;
if (item.onClick) {
shouldDismiss = !!item.onClick(ev, item);
}
else if (props.onItemClick) {
shouldDismiss = !!props.onItemClick(ev, item);
}
if (shouldDismiss || !ev.defaultPrevented) {
dismiss(ev, true);
}
};
return [
onItemMouseEnterBase,
onItemMouseMoveBase,
onMouseItemLeave,
onItemClick,
onAnchorClick,
executeItemClick,
onItemClickBase,
];
}
//#endregion
exports.ContextualMenuBase = React.memo(React.forwardRef(function (propsWithoutDefaults, forwardedRef) {
var _a;
var _b = (0, Utilities_1.getPropsWithDefaults)(DEFAULT_PROPS, propsWithoutDefaults), ref = _b.ref, props = tslib_1.__rest(_b, ["ref"]);
var hostElement = React.useRef(null);
var asyncTracker = (0, react_hooks_1.useAsync)();
var menuId = (0, react_hooks_1.useId)(COMPONENT_NAME, props.id);
(0, react_hooks_1.useWarnings)({
name: COMPONENT_NAME,
props: props,
deprecations: {
getMenuClassNames: 'styles',
},
});
var dismiss = function (ev, dismissAll) { var _a; return (_a = props.onDismiss) === null || _a === void 0 ? void 0 : _a.call(props, ev, dismissAll); };
var _c = (0, react_hooks_1.useTarget)(props.target, hostElement), targetRef = _c[0], targetWindow = _c[1];
var tryFocusPreviousActiveElement = usePreviousActiveElement(props, targetWindow, hostElement)[0];
var _d = useSubMenuState(props, dismiss), expandedMenuItemKey = _d[0], openSubMenu = _d[1], getSubmenuProps = _d[2], onSubMenuDismiss = _d[3];
var _e = useShouldUpdateFocusOnMouseMove(props), shouldUpdateFocusOnMouseEvent = _e[0], gotMouseMove = _e[1], onMenuFocusCapture = _e[2];
var _f = useScrollHandler(asyncTracker), onScroll = _f[0], isScrollIdle = _f[1];
var _g = useSubmenuEnterTimer(props, asyncTracker), cancelSubMenuTimer = _g[0], startSubmenuTimer = _g[1], subMenuEntryTimer = _g[2];
var responsiveMode = (0, ResponsiveMode_1.useResponsiveMode)(hostElement, props.responsiveMode);
useVisibility(props, targetWindow);
var _h = useKeyHandlers(props, dismiss, hostElement, openSubMenu), onKeyDown = _h[0], onKeyUp = _h[1], onMenuKeyDown = _h[2], onItemKeyDown = _h[3];
var _j = useMouseHandlers(props, isScrollIdle, subMenuEntryTimer, targetWindow, shouldUpdateFocusOnMouseEvent, gotMouseMove, expandedMenuItemKey, hostElement, startSubmenuTimer, cancelSubMenuTimer, openSubMenu, onSubMenuDismiss, dismiss), onItemMouseEnterBase = _j[0], onItemMouseMoveBase = _j[1], onMouseItemLeave = _j[2], onItemClick = _j[3], onAnchorClick = _j[4], executeItemClick = _j[5], onItemClickBase = _j[6];
//#region Render helpers
var onDefaultRenderMenuList = function (menuListProps,
// eslint-disable-next-line @typescript-eslint/no-deprecated
menuClassNames, defaultRender) {
var indexCorrection = 0;
var items = menuListProps.items, totalItemCount = menuListProps.totalItemCount, hasCheckmarks = menuListProps.hasCheckmarks, hasIcons = menuListProps.hasIcons;
return (React.createElement("ul", { className: menuClassNames.list, onKeyDown: onKeyDown, onKeyUp: onKeyUp, role: 'presentation' }, items.map(function (item, index) {
var menuItem = renderMenuItem(item, index, indexCorrection, totalItemCount, hasCheckmarks, hasIcons, menuClassNames);
if (item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Divider && item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Header) {
var indexIncrease = item.customOnRenderListLength ? item.customOnRenderListLength : 1;
indexCorrection += indexIncrease;
}
return menuItem;
})));
};
var renderFocusZone = function (children, adjustedFocusZoneProps) {
var _a = props.focusZoneAs, ChildrenRenderer = _a === void 0 ? FocusZone_1.FocusZone : _a;
return React.createElement(ChildrenRenderer, tslib_1.__assign({}, adjustedFocusZoneProps), children);
};
/**
* !!!IMPORTANT!!! Avoid mutating `item: IContextualMenuItem` argument. It will
* cause the menu items to always re-render because the component update is based on shallow comparison.
*/
var renderMenuItem = function (item, index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons,
// eslint-disable-next-line @typescript-eslint/no-deprecated
menuClassNames) {
var _a;
var renderedItems = [];
var iconProps = item.iconProps || { iconName: 'None' };
var getItemClassNames = item.getItemClassNames, // eslint-disable-line @typescript-eslint/no-deprecated
itemProps = item.itemProps;
var styles = itemProps ? itemProps.styles : undefined;
// We only send a dividerClassName when the item to be rendered is a divider.
// For all other cases, the default divider style is used.
var dividerClassName = item.itemType === ContextualMenu_types_1.ContextualMenuItemType.Divider ? item.className : undefined;
var subMenuIconClassName = item.submenuIconProps ? item.submenuIconProps.className : '';
// eslint-disable-next-line @typescript-eslint/no-deprecated
var itemClassNames;
// IContextualMenuItem#getItemClassNames for backwards compatibility
// otherwise uses mergeStyles for class names.
if (getItemClassNames) {
itemClassNames = getItemClassNames(props.theme, (0, index_1.isItemDisabled)(item), expandedMenuItemKey === item.key, !!(0, index_1.getIsChecked)(item), !!item.href, iconProps.iconName !== 'None', item.className, dividerClassName, iconProps.className, subMenuIconClassName, item.primaryDisabled);
}
else {
var itemStyleProps = {
theme: props.theme,
disabled: (0, index_1.isItemDisabled)(item),
expanded: expandedMenuItemKey === item.key,
checked: !!(0, index_1.getIsChecked)(item),
isAnchorLink: !!item.href,
knownIcon: iconProps.iconName !== 'None',
itemClassName: item.className,
dividerClassName: dividerClassName,
iconClassName: iconProps.className,
subMenuClassName: subMenuIconClassName,
primaryDisabled: item.primaryDisabled,
};
// We need to generate default styles then override if styles are provided
// since the ContextualMenu currently handles item classNames.
itemClassNames = getContextualMenuItemClassNames(_getMenuItemStylesFunction((_a = menuClassNames.subComponentStyles) === null || _a === void 0 ? void 0 : _a.menuItem, styles), itemStyleProps);
}
// eslint-disable-next-line @typescript-eslint/no-deprecated
if (item.text === '-' || item.name === '-') {
item.itemType = ContextualMenu_types_1.ContextualMenuItemType.Divider;
}
switch (item.itemType) {
case ContextualMenu_types_1.ContextualMenuItemType.Divider:
renderedItems.push(renderSeparator(index, itemClassNames));
break;
case ContextualMenu_types_1.ContextualMenuItemType.Header:
renderedItems.push(renderSeparator(index, itemClassNames));
var headerItem = renderHeaderMenuItem(item, itemClassNames, menuClassNames, index, hasCheckmarks, hasIcons);
renderedItems.push(renderListItem(headerItem, item.key || index, itemClassNames, item.title));
break;
case ContextualMenu_types_1.ContextualMenuItemType.Section:
renderedItems.push(renderSectionItem(item, itemClassNames, menuClassNames, index, hasCheckmarks, hasIcons));
break;
default:
var defaultRenderNormalItem = function () {
return renderNormalItem(item, itemClassNames, index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons);
};
var menuItem = props.onRenderContextualMenuItem
? props.onRenderContextualMenuItem(item, defaultRenderNormalItem)
: defaultRenderNormalItem();
renderedItems.push(renderListItem(menuItem, item.key || index, itemClassNames, item.title));
break;
}
// Since multiple nodes *could* be rendered, wrap them all in a fragment with this item's key.
// This ensures the reconciler handles multi-item output per-node correctly and does not re-mount content.
return React.createElement(React.Fragment, { key: item.key }, renderedItems);
};
var defaultMenuItemRenderer = function (item,
// eslint-disable-next-line @typescript-eslint/no-deprecated
menuClassNames) {
var index = item.index, focusableElementIndex = item.focusableElementIndex, totalItemCount = item.totalItemCount, hasCheckmarks = item.hasCheckmarks, hasIcons = item.hasIcons;
return renderMenuItem(item, index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons, menuClassNames);
};
var renderSectionItem = function (sectionItem,
// eslint-disable-next-line @typescript-eslint/no-deprecated
itemClassNames,
// eslint-disable-next-line @typescript-eslint/no-deprecated
menuClassNames, index, hasCheckmarks, hasIcons) {
var sectionProps = sectionItem.sectionProps;
if (!sectionProps) {
return;
}
var headerItem;
var groupProps;
if (sectionProps.title) {
var headerContextualMenuItem = undefined;
var ariaLabelledby = '';
if (typeof sectionProps.title === 'string') {
// Since title is a user-facing string, it needs to be stripped
// of whitespace in order to build a valid element ID
var id_1 = menuId + sectionProps.title.replace(/\s/g, '');
headerContextualMenuItem = {
key: "section-".concat(sectionProps.title, "-title"),
itemType: ContextualMenu_types_1.ContextualMenuItemType.Header,
text: sectionProps.title,
id: id_1,
};
ariaLabelledby = id_1;
}
else {
var id_2 = sectionProps.title.id || menuId + sectionProps.title.key.replace(/\s/g, '');
headerContextualMenuItem = tslib_1.__assign(tslib_1.__assign({}, sectionProps.title), { id: id_2 });
ariaLabelledby = id_2;
}
if (headerContextualMenuItem) {
groupProps = {
role: 'group',
'aria-labelledby': ariaLabelledby,
};
headerItem = renderHeaderMenuItem(headerContextualMenuItem, itemClassNames, menuClassNames, index, hasCheckmarks, hasIcons);
}
}
if (sectionProps.items && sectionProps.items.length > 0) {
var correctedIndex_1 = 0;
return (React.createElement("li", { role: "presentation", key: sectionProps.key || sectionItem.key || "section-".concat(index) },
React.createElement("div", tslib_1.__assign({}, groupProps),
React.createElement("ul", { className: menuClassNames.list, role: "presentation" },
sectionProps.topDivider && renderSeparator(index, itemClassNames, true, true),
headerItem && renderListItem(headerItem, sectionItem.key || index, itemClassNames, sectionItem.title),
sectionProps.items.map(function (contextualMenuItem, itemsIndex) {
var menuItem = renderMenuItem(contextualMenuItem, itemsIndex, correctedIndex_1, getItemCount(sectionProps.items), hasCheckmarks, hasIcons, menuClassNames);
if (contextualMenuItem.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Divider &&
contextualMenuItem.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Header) {
var indexIncrease = contextualMenuItem.customOnRenderListLength
? contextualMenuItem.customOnRenderListLength
: 1;
correctedIndex_1 += indexIncrease;
}
return menuItem;
}),
sectionProps.bottomDivider && renderSeparator(index, itemClassNames, false, true)))));
}
};
var renderListItem = function (content, key, classNames, // eslint-disable-line @typescript-eslint/no-deprecated
title) {
return (React.createElement("li", { role: "presentation", title: title, key: key, className: classNames.item }, content));
};
var renderSeparator = function (index, classNames, // eslint-disable-line @typescript-eslint/no-deprecated
top, fromSection) {
if (fromSection || index > 0) {
return (React.createElement("li", { role: "separator", key: 'separator-' + index + (top === undefined ? '' : top ? '-top' : '-bottom'), className: classNames.divider, "aria-hidden": "true" }));
}
return null;
};
var renderNormalItem = function (item, classNames, // eslint-disable-line @typescript-eslint/no-deprecated
index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons) {
if (item.onRender) {
return item.onRender(tslib_1.__assign({ 'aria-posinset': focusableElementIndex + 1, 'aria-setsize': totalItemCount }, item), dismiss);
}
var contextualMenuItemAs = props.contextualMenuItemAs;
var commonProps = {
item: item,
classNames: classNames,
index: index,
focusableElementIndex: focusableElementIndex,
totalItemCount: totalItemCount,
hasCheckmarks: hasCheckmarks,
hasIcons: hasIcons,
contextualMenuItemAs: contextualMenuItemAs,
onItemMouseEnter: onItemMouseEnterBase,
onItemMouseLeave: onMouseItemLeave,
onItemMouseMove: onItemMouseMoveBase,
onItemMouseDown: onItemMouseDown,
executeItemClick: executeItemClick,
onItemKeyDown: onItemKeyDown,
expandedMenuItemKey: expandedMenuItemKey,
openSubMenu: openSubMenu,
dismissSubMenu: onSubMenuDismiss,
dismissMenu: dismiss,
};
if (item.href) {
var ContextualMenuAnchorAs = index_2.ContextualMenuAnchor;
if (item.contextualMenuItemWrapperAs) {
ContextualMenuAnchorAs = (0, Utilities_1.composeComponentAs)(item.contextualMenuItemWrapperAs, ContextualMenuAnchorAs);
}
return React.createElement(ContextualMenuAnchorAs, tslib_1.__assign({}, commonProps, { onItemClick: onAnchorClick }));
}
if (item.split && (0, index_1.hasSubmenu)(item)) {
var ContextualMenuSplitButtonAs = index_2.ContextualMenuSplitButton;
if (item.contextualMenuItemWrapperAs) {
ContextualMenuSplitButtonAs = (0, Utilities_1.composeComponentAs)(item.contextualMenuItemWrapperAs, ContextualMenuSplitButtonAs);
}
return (React.createElement(ContextualMenuSplitButtonAs, tslib_1.__assign({}, commonProps, { onItemClick: onItemClick, onItemClickBase: onItemClickBase, onTap: cancelSubMenuTimer })));
}
var ContextualMenuButtonAs = index_2.ContextualMenuButton;
if (item.contextualMenuItemWrapperAs) {
ContextualMenuButtonAs = (0, Utilities_1.composeComponentAs)(item.contextualMenuItemWrapperAs, ContextualMenuButtonAs);
}
return React.createElement(ContextualMenuButtonAs, tslib_1.__assign({}, commonProps, { onItemClick: onItemClick, onItemClickBase: onItemClickBase }));
};
var renderHeaderMenuItem = function (item,
// eslint-disable-next-line @typescript-eslint/no-deprecated
itemClassNames,
// eslint-disable-next-line @typescript-eslint/no-deprecated
menuClassNames, index, hasCheckmarks, hasIcons) {
var ChildrenRenderer = ContextualMenuItem_1.ContextualMenuItem;
if (item.contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(item.contextualMenuItemAs, ChildrenRenderer);
}
if (props.contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(props.contextualMenuItemAs, ChildrenRenderer);
}
var itemProps = item.itemProps, id = item.id;
var divHtmlProperties = itemProps && (0, Utilities_1.getNativeProps)(itemProps, Utilities_1.divProperties);
return (
// eslint-disable-next-line @typescript-eslint/no-deprecated
React.createElement("div", tslib_1.__assign({ id: id, className: menuClassNames.header }, divHtmlProperties, { style: item.style }),
React.createElement(ChildrenRenderer, tslib_1.__assign({ item: item, classNames: itemClassNames, index: index, onCheckmarkClick: hasCheckmarks ? onItemClick : undefined, hasIcons: hasIcons }, itemProps))));
};
//#endregion
//#region Main render
var isBeakVisible = props.isBeakVisible;
var items = props.items, labelElementId = props.labelElementId, id = props.id, className = props.className, beakWidth = props.beakWidth, directionalHint = props.directionalHint, directionalHintForRTL = props.directionalHintForRTL, alignTargetEdge = props.alignTargetEdge, gapSpace = props.gapSpace, coverTarget = props.coverTarget, ariaLabel = props.ariaLabel, doNotLayer = props.doNotLayer, target = props.target, bounds = props.bounds, useTargetWidth = props.useTargetWidth, useTargetAsMinWidth = props.useTargetAsMinWidth, directionalHintFixed = props.directionalHintFixed, shouldFocusOnMount = props.shouldFocusOnMount, shouldFocusOnContainer = props.shouldFocusOnContainer, title = props.title, styles = props.styles, theme = props.theme, calloutProps = props.calloutProps, _k = props.onRenderSubMenu, onRenderSubMenu = _k === void 0 ? onDefaultRenderSubMenu : _k, _l = props.onRenderMenuList, onRenderMenuList = _l === void 0 ? function (menuListProps, defaultRender) { return onDefaultRenderMenuList(menuListProps, classNames, defaultRender); } : _l, focusZoneProps = props.focusZoneProps,
// eslint-disable-next-line @typescript-eslint/no-deprecated
getMenuClassNames = props.getMenuClassNames;
var classNames = getMenuClassNames
? getMenuClassNames(theme, className)
: getClassNames(styles, {
theme: theme,
className: className,
});
var hasIcons = itemsHaveIcons(items);
function itemsHaveIcons(contextualMenuItems) {
for (var _i = 0, contextualMenuItems_1 = contextualMenuItems; _i < contextualMenuItems_1.length; _i++) {
var item = contextualMenuItems_1[_i];
if (item.iconProps) {
return true;
}
if (item.itemType === ContextualMenu_types_1.ContextualMenuItemType.Section &&
item.sectionProps &&
itemsHaveIcons(item.sectionProps.items)) {
return true;
}
}
return false;
}
var adjustedFocusZoneProps = tslib_1.__assign(tslib_1.__assign({ direction: FocusZone_1.FocusZoneDirection.vertical, handleTabKey: FocusZone_1.FocusZoneTabbableElements.all, isCircularNavigation: true, 'data-tabster': '{"uncontrolled": {}, "focusable": { "excludeFromMover": true }}' }, focusZoneProps), { className: (0, Utilities_1.css)(classNames.root, (_a = props.focusZoneProps) === null || _a === void 0 ? void 0 : _a.className) });
var hasCheckmarks = canAnyMenuItemsCheck(items);
var submenuProps = expandedMenuItemKey && props.hidden !== true ? getSubmenuProps() : null;
isBeakVisible = isBeakVisible === undefined ? responsiveMode <= ResponsiveMode_1.ResponsiveMode.medium : isBeakVisible;
/**
* When useTargetWidth is true, get the width of the target element and apply it for the context menu container
*/
var contextMenuStyle;
var targetAsHtmlElement = targetRef.current;
if ((useTargetWidth || useTargetAsMinWidth) && targetAsHtmlElement && targetAsHtmlElement.offsetWidth) {
var targetBoundingRect = targetAsHtmlElement.getBoundingClientRect();
var targetWidth = targetBoundingRect.width - 2; /* Accounts for 1px border */
if (useTargetWidth) {
contextMenuStyle = {
width: targetWidth,
};
}
else if (useTargetAsMinWidth) {
contextMenuStyle = {
minWidth: targetWidth,
};
}
}
// The menu should only return if items were provided, if no items were provided then it should not appear.
if (items && items.length > 0) {
var totalItemCount_1 = getItemCount(items);
var calloutStyles_1 = classNames.subComponentStyles
? classNames.subComponentStyles.callout
: undefined;
return (React.createElement(index_3.MenuContext.Consumer, null, function (menuContext) { return (React.createElement(Callout_1.Callout, tslib_1.__assign({ styles: calloutStyles_1, onRestoreFocus: tryFocusPreviousActiveElement }, calloutProps, { target: target || menuContext.target, isBeakVisible: isBeakVisible, beakWidth: beakWidth, directionalHint: directionalHint, directionalHintForRTL: directionalHintForRTL, gapSpace: gapSpace, coverTarget: coverTarget, doNotLayer: doNotLayer, className: (0, Utilities_1.css)('ms-ContextualMenu-Callout', calloutProps && calloutProps.className), setInitialFocus: shouldFocusOnMount, onDismiss: props.onDismiss || menuContext.onDismiss, onScroll: onScroll, bounds: bounds, directionalHintFixed: directionalHintFixed, alignTargetEdge: alignTargetEdge, hidden: props.hidden || menuContext.hidden, ref: forwardedRef }),
React.createElement("div", { style: contextMenuStyle, ref: hostElement, id: id, className: classNames.container, tabIndex: shouldFocusOnContainer ? 0 : -1, onKeyDown: onMenuKeyDown, onKeyUp: onKeyUp, onFocusCapture: onMenuFocusCapture, "aria-label": ariaLabel, "aria-labelledby": labelElementId, role: 'menu' },
title && React.createElement("div", { className: classNames.title },
" ",
title,
" "),
items && items.length
? renderFocusZone(onRenderMenuList({
ariaLabel: ariaLabel,
items: items,
totalItemCount: totalItemCount_1,
hasCheckmarks: hasCheckmarks,
hasIcons: hasIcons,
defaultMenuItemRenderer: function (item) {
return defaultMenuItemRenderer(item, classNames);
},
labelElementId: labelElementId,
}, function (menuListProps, defaultRender) { return onDefaultRenderMenuList(menuListProps, classNames, defaultRender); }), adjustedFocusZoneProps)
: null,
submenuProps && onRenderSubMenu(submenuProps, onDefaultRenderSubMenu)),
React.createElement(Utilities_1.FocusRects, null))); }));
}
else {
return null;
}
//#endregion
}), function (prevProps, newProps) {
if (!newProps.shouldUpdateWhenHidden && prevProps.hidden && newProps.hidden) {
// Do not update when hidden.
return true;
}
return (0, Utilities_1.shallowCompare)(prevProps, newProps);
});
exports.ContextualMenuBase.displayName = 'ContextualMenuBase';
/**
* Returns true if the key for the event is alt (Mac option) or meta (Mac command).
*/
function isAltOrMeta(ev) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
return ev.which === Utilities_1.KeyCodes.alt || ev.key === 'Meta';
}
function onItemMouseDown(item, ev) {
var _a;
(_a = item.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(item, item, ev);
}
function onDefaultRenderSubMenu(subMenuProps, defaultRender) {
throw Error('ContextualMenuBase: onRenderSubMenu callback is null or undefined. ' +
'Please ensure to set `onRenderSubMenu` property either manually or with `styled` helper.');
}
/**
* Returns the item that matches a given key if any.
* @param key - The key of the item to match
* @param items - The items to look for the key
*/
function findItemByKeyFromItems(key, items) {
for (var _i = 0, items_3 = items; _i < items_3.length; _i++) {
var item = items_3[_i];
if (item.itemType === ContextualMenu_types_1.ContextualMenuItemType.Section && item.sectionProps) {
var match = findItemByKeyFromItems(key, item.sectionProps.items);
if (match) {
return match;
}
}
else if (item.key && item.key === key) {
return item;
}
}
}
function getOnClickWithOverrideTarget(onClick, target) {
return onClick
? function (ev, item) {
overrideTarget(ev, target);
return onClick(ev, item);
}
: onClick;
}
function overrideTarget(ev, target) {
if (ev && target) {
ev.persist();
if (target instanceof Event) {
ev.target = target.target;
}
else if (target instanceof Element) {
ev.target = target;
}
}
}
//# sourceMappingURL=ContextualMenu.base.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,50 @@
import type { ITheme } from '../../Styling';
import type { IVerticalDividerClassNames } from '../Divider/VerticalDivider.types';
import type { IContextualMenuItemStyles, IContextualMenuItemStyleProps } from './ContextualMenuItem.types';
import type { IContextualMenuSubComponentStyles } from './ContextualMenu.types';
/**
* @deprecated Deprecated in favor of mergeStyles API.
*/
export interface IContextualMenuClassNames {
container?: string;
root?: string;
list?: string;
header?: string;
title?: string;
subComponentStyles?: IContextualMenuSubComponentStyles;
}
/**
* @deprecated Deprecated in favor of mergeStyles API.
*/
export interface IMenuItemClassNames {
item?: string;
divider?: string;
root?: string;
linkContent?: string;
icon?: string;
checkmarkIcon?: string;
subMenuIcon?: string;
label?: string;
secondaryText?: string;
splitContainer?: string;
splitPrimary?: string;
splitMenu?: string;
linkContentMenu?: string;
screenReaderText?: string;
}
export declare const getSplitButtonVerticalDividerClassNames: (theme: ITheme) => IVerticalDividerClassNames;
/**
* @deprecated Will be removed in \>= 7.0.
* This is a package-internal method that has been depended on.
* It is being kept in this form for backwards compatibility.
* @internal
*/
export declare const getItemClassNames: (theme: ITheme, disabled: boolean, expanded: boolean, checked: boolean, isAnchorLink: boolean, knownIcon: boolean, itemClassName?: string, dividerClassName?: string, iconClassName?: string, subMenuClassName?: string, primaryDisabled?: boolean, className?: string) => IContextualMenuItemStyles;
/**
* Wrapper function for generating ContextualMenuItem classNames which adheres to
* the getStyles API, but invokes memoized className generator function with
* primitive values.
*
* @param props - the ContextualMenuItem style props used to generate its styles.
*/
export declare const getItemStyles: (props: IContextualMenuItemStyleProps) => IContextualMenuItemStyles;
@@ -0,0 +1,199 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getItemStyles = exports.getItemClassNames = exports.getSplitButtonVerticalDividerClassNames = void 0;
var VerticalDivider_classNames_1 = require("../Divider/VerticalDivider.classNames");
var ContextualMenu_cnstyles_1 = require("./ContextualMenu.cnstyles");
var Styling_1 = require("../../Styling");
var Utilities_1 = require("../../Utilities");
var CONTEXTUAL_SPLIT_MENU_MINWIDTH = '28px';
var MediumScreenSelector = (0, Styling_1.getScreenSelector)(0, Styling_1.ScreenWidthMaxMedium);
exports.getSplitButtonVerticalDividerClassNames = (0, Utilities_1.memoizeFunction)(
/* eslint-disable @typescript-eslint/no-deprecated */
function (theme) {
var _a;
return (0, Styling_1.mergeStyleSets)((0, VerticalDivider_classNames_1.getDividerClassNames)(theme), {
/* eslint-enable @typescript-eslint/no-deprecated */
wrapper: {
position: 'absolute',
right: 28, // width of the splitMenu based on the padding plus icon fontSize
selectors: (_a = {},
_a[MediumScreenSelector] = {
right: 32, // fontSize of the icon increased from 12px to 16px
},
_a),
},
divider: {
height: 16,
width: 1,
},
});
});
var GlobalClassNames = {
item: 'ms-ContextualMenu-item',
divider: 'ms-ContextualMenu-divider',
root: 'ms-ContextualMenu-link',
isChecked: 'is-checked',
isExpanded: 'is-expanded',
isDisabled: 'is-disabled',
linkContent: 'ms-ContextualMenu-linkContent',
linkContentMenu: 'ms-ContextualMenu-linkContent',
icon: 'ms-ContextualMenu-icon',
iconColor: 'ms-ContextualMenu-iconColor',
checkmarkIcon: 'ms-ContextualMenu-checkmarkIcon',
subMenuIcon: 'ms-ContextualMenu-submenuIcon',
label: 'ms-ContextualMenu-itemText',
secondaryText: 'ms-ContextualMenu-secondaryText',
splitMenu: 'ms-ContextualMenu-splitMenu',
screenReaderText: 'ms-ContextualMenu-screenReaderText',
};
/**
* @deprecated Will be removed in \>= 7.0.
* This is a package-internal method that has been depended on.
* It is being kept in this form for backwards compatibility.
* @internal
*/
// TODO: Audit perf. impact of and potentially remove memoizeFunction.
// https://github.com/microsoft/fluentui/issues/5534
exports.getItemClassNames = (0, Utilities_1.memoizeFunction)(function (theme, disabled, expanded, checked, isAnchorLink, knownIcon, itemClassName, dividerClassName, iconClassName, subMenuClassName, primaryDisabled, className) {
var _a, _b, _c, _d;
var styles = (0, ContextualMenu_cnstyles_1.getMenuItemStyles)(theme);
var classNames = (0, Styling_1.getGlobalClassNames)(GlobalClassNames, theme);
return (0, Styling_1.mergeStyleSets)({
item: [classNames.item, styles.item, itemClassName],
divider: [classNames.divider, styles.divider, dividerClassName],
root: [
classNames.root,
styles.root,
checked && [classNames.isChecked, styles.rootChecked],
isAnchorLink && styles.anchorLink,
expanded && [classNames.isExpanded, styles.rootExpanded],
disabled && [classNames.isDisabled, styles.rootDisabled],
!disabled &&
!expanded && [
{
selectors: (_a = {
':hover': styles.rootHovered,
':active': styles.rootPressed
},
// eslint-disable-next-line @fluentui/max-len
_a[".".concat(Utilities_1.IsFocusVisibleClassName, " &:focus, .").concat(Utilities_1.IsFocusVisibleClassName, " &:focus:hover, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus:hover")] = styles.rootFocused,
_a[".".concat(Utilities_1.IsFocusVisibleClassName, " &:hover, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:hover")] = {
background: 'inherit;',
},
_a),
},
],
className,
],
splitPrimary: [
styles.root,
{
width: "calc(100% - ".concat(CONTEXTUAL_SPLIT_MENU_MINWIDTH, ")"),
},
checked && ['is-checked', styles.rootChecked],
(disabled || primaryDisabled) && ['is-disabled', styles.rootDisabled],
!(disabled || primaryDisabled) &&
!checked && [
{
selectors: (_b = {
':hover': styles.rootHovered
},
// when hovering over the splitPrimary also affect the splitMenu
_b[":hover ~ .".concat(classNames.splitMenu)] = styles.rootHovered,
_b[':active'] = styles.rootPressed,
// eslint-disable-next-line @fluentui/max-len
_b[".".concat(Utilities_1.IsFocusVisibleClassName, " &:focus, .").concat(Utilities_1.IsFocusVisibleClassName, " &:focus:hover, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus:hover")] = styles.rootFocused,
_b[".".concat(Utilities_1.IsFocusVisibleClassName, " &:hover, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:hover")] = {
background: 'inherit;',
},
_b),
},
],
],
splitMenu: [
classNames.splitMenu,
styles.root,
{
flexBasis: '0',
padding: '0 8px',
minWidth: CONTEXTUAL_SPLIT_MENU_MINWIDTH,
},
expanded && ['is-expanded', styles.rootExpanded],
disabled && ['is-disabled', styles.rootDisabled],
!disabled &&
!expanded && [
{
selectors: (_c = {
':hover': styles.rootHovered,
':active': styles.rootPressed
},
// eslint-disable-next-line @fluentui/max-len
_c[".".concat(Utilities_1.IsFocusVisibleClassName, " &:focus, .").concat(Utilities_1.IsFocusVisibleClassName, " &:focus:hover, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus:hover")] = styles.rootFocused,
_c[".".concat(Utilities_1.IsFocusVisibleClassName, " &:hover, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:hover")] = {
background: 'inherit;',
},
_c),
},
],
],
anchorLink: styles.anchorLink,
linkContent: [classNames.linkContent, styles.linkContent],
linkContentMenu: [
classNames.linkContentMenu,
styles.linkContent,
{
justifyContent: 'center',
},
],
icon: [
classNames.icon,
knownIcon && styles.iconColor,
styles.icon,
iconClassName,
disabled && [classNames.isDisabled, styles.iconDisabled],
],
iconColor: styles.iconColor,
checkmarkIcon: [classNames.checkmarkIcon, knownIcon && styles.checkmarkIcon, styles.icon, iconClassName],
subMenuIcon: [
classNames.subMenuIcon,
styles.subMenuIcon,
subMenuClassName,
expanded && { color: theme.palette.neutralPrimary },
disabled && [styles.iconDisabled],
],
label: [classNames.label, styles.label],
secondaryText: [classNames.secondaryText, styles.secondaryText],
splitContainer: [
styles.splitButtonFlexContainer,
!disabled &&
!checked && [
{
selectors: (_d = {},
// eslint-disable-next-line @fluentui/max-len
_d[".".concat(Utilities_1.IsFocusVisibleClassName, " &:focus, .").concat(Utilities_1.IsFocusVisibleClassName, " &:focus:hover, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus, :host(.").concat(Utilities_1.IsFocusVisibleClassName, ") &:focus:hover")] = styles.rootFocused,
_d),
},
],
],
screenReaderText: [
classNames.screenReaderText,
styles.screenReaderText,
Styling_1.hiddenContentStyle,
{ visibility: 'hidden' },
],
});
});
/**
* Wrapper function for generating ContextualMenuItem classNames which adheres to
* the getStyles API, but invokes memoized className generator function with
* primitive values.
*
* @param props - the ContextualMenuItem style props used to generate its styles.
*/
var getItemStyles = function (props) {
var theme = props.theme, disabled = props.disabled, expanded = props.expanded, checked = props.checked, isAnchorLink = props.isAnchorLink, knownIcon = props.knownIcon, itemClassName = props.itemClassName, dividerClassName = props.dividerClassName, iconClassName = props.iconClassName, subMenuClassName = props.subMenuClassName, primaryDisabled = props.primaryDisabled, className = props.className;
// eslint-disable-next-line @typescript-eslint/no-deprecated
return (0, exports.getItemClassNames)(theme, disabled, expanded, checked, isAnchorLink, knownIcon, itemClassName, dividerClassName, iconClassName, subMenuClassName, primaryDisabled, className);
};
exports.getItemStyles = getItemStyles;
//# sourceMappingURL=ContextualMenu.classNames.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
import type { ITheme } from '../../Styling';
import type { IMenuItemStyles } from './ContextualMenu.types';
export declare const CONTEXTUAL_MENU_ITEM_HEIGHT = 36;
export declare const getMenuItemStyles: (theme: ITheme) => IMenuItemStyles;
@@ -0,0 +1,199 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMenuItemStyles = exports.CONTEXTUAL_MENU_ITEM_HEIGHT = void 0;
var tslib_1 = require("tslib");
var Styling_1 = require("../../Styling");
var Utilities_1 = require("../../Utilities");
exports.CONTEXTUAL_MENU_ITEM_HEIGHT = 36;
var MediumScreenSelector = (0, Styling_1.getScreenSelector)(0, Styling_1.ScreenWidthMaxMedium);
exports.getMenuItemStyles = (0, Utilities_1.memoizeFunction)(function (theme) {
var _a, _b, _c, _d, _e;
var semanticColors = theme.semanticColors, fonts = theme.fonts, palette = theme.palette;
var ContextualMenuItemBackgroundHoverColor = semanticColors.menuItemBackgroundHovered;
var ContextualMenuItemTextHoverColor = semanticColors.menuItemTextHovered;
var ContextualMenuItemBackgroundSelectedColor = semanticColors.menuItemBackgroundPressed;
var ContextualMenuItemDividerColor = semanticColors.bodyDivider;
var menuItemStyles = {
item: [
fonts.medium,
{
color: semanticColors.bodyText,
position: 'relative',
boxSizing: 'border-box',
},
],
divider: {
display: 'block',
height: '1px',
backgroundColor: ContextualMenuItemDividerColor,
position: 'relative',
},
root: [
(0, Styling_1.getFocusStyle)(theme),
fonts.medium,
{
color: semanticColors.bodyText,
backgroundColor: 'transparent',
border: 'none',
width: '100%',
height: exports.CONTEXTUAL_MENU_ITEM_HEIGHT,
lineHeight: exports.CONTEXTUAL_MENU_ITEM_HEIGHT,
display: 'block',
cursor: 'pointer',
padding: '0px 8px 0 4px', // inner elements have a margin of 4px (4 + 4 = 8px as on right side)
textAlign: 'left',
},
],
rootDisabled: {
color: semanticColors.disabledBodyText,
cursor: 'default',
pointerEvents: 'none',
selectors: (_a = {},
_a[Styling_1.HighContrastSelector] = {
// ensure disabled text looks different than enabled
color: 'GrayText',
opacity: 1,
},
_a),
},
rootHovered: {
backgroundColor: ContextualMenuItemBackgroundHoverColor,
color: ContextualMenuItemTextHoverColor,
selectors: {
'.ms-ContextualMenu-icon': {
color: palette.themeDarkAlt,
},
'.ms-ContextualMenu-submenuIcon': {
color: palette.neutralPrimary,
},
},
},
rootFocused: {
backgroundColor: palette.white,
},
rootChecked: {
selectors: {
'.ms-ContextualMenu-checkmarkIcon': {
color: palette.neutralPrimary,
},
},
},
rootPressed: {
backgroundColor: ContextualMenuItemBackgroundSelectedColor,
selectors: {
'.ms-ContextualMenu-icon': {
color: palette.themeDark,
},
'.ms-ContextualMenu-submenuIcon': {
color: palette.neutralPrimary,
},
},
},
rootExpanded: {
backgroundColor: ContextualMenuItemBackgroundSelectedColor,
color: semanticColors.bodyTextChecked,
selectors: (_b = {
'.ms-ContextualMenu-submenuIcon': (_c = {},
_c[Styling_1.HighContrastSelector] = {
// icons inside of anchor tags are not properly inheriting color in high contrast
color: 'inherit',
},
_c)
},
_b[Styling_1.HighContrastSelector] = tslib_1.__assign({}, (0, Styling_1.getHighContrastNoAdjustStyle)()),
_b),
},
linkContent: {
whiteSpace: 'nowrap',
height: 'inherit',
display: 'flex',
alignItems: 'center',
maxWidth: '100%',
},
anchorLink: {
padding: '0px 8px 0 4px', // inner elements have a margin of 4px (4 + 4 = 8px as on right side)
textRendering: 'auto',
color: 'inherit',
letterSpacing: 'normal',
wordSpacing: 'normal',
textTransform: 'none',
textIndent: '0px',
textShadow: 'none',
textDecoration: 'none',
boxSizing: 'border-box',
},
label: {
margin: '0 4px',
verticalAlign: 'middle',
display: 'inline-block',
flexGrow: '1',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
},
secondaryText: {
color: theme.palette.neutralSecondary,
paddingLeft: '20px',
textAlign: 'right',
},
icon: {
display: 'inline-block',
minHeight: '1px',
maxHeight: exports.CONTEXTUAL_MENU_ITEM_HEIGHT,
fontSize: Styling_1.IconFontSizes.medium,
width: Styling_1.IconFontSizes.medium,
margin: '0 4px',
verticalAlign: 'middle',
flexShrink: '0',
selectors: (_d = {},
_d[MediumScreenSelector] = {
fontSize: Styling_1.IconFontSizes.large,
width: Styling_1.IconFontSizes.large,
},
_d),
},
iconColor: {
color: semanticColors.menuIcon,
},
iconDisabled: {
color: semanticColors.disabledBodyText,
},
checkmarkIcon: {
color: semanticColors.bodySubtext,
},
subMenuIcon: {
height: exports.CONTEXTUAL_MENU_ITEM_HEIGHT,
lineHeight: exports.CONTEXTUAL_MENU_ITEM_HEIGHT,
color: palette.neutralSecondary,
textAlign: 'center',
display: 'inline-block',
verticalAlign: 'middle',
flexShrink: '0',
fontSize: Styling_1.IconFontSizes.small, // 12px
selectors: (_e = {
':hover': {
color: palette.neutralPrimary,
},
':active': {
color: palette.neutralPrimary,
}
},
_e[MediumScreenSelector] = {
fontSize: Styling_1.IconFontSizes.medium, // 16px
},
_e),
},
splitButtonFlexContainer: [
(0, Styling_1.getFocusStyle)(theme),
{
display: 'flex',
height: exports.CONTEXTUAL_MENU_ITEM_HEIGHT,
flexWrap: 'nowrap',
justifyContent: 'center',
alignItems: 'flex-start',
},
],
};
return (0, Styling_1.concatStyleSets)(menuItemStyles);
});
//# sourceMappingURL=ContextualMenu.cnstyles.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
import * as React from 'react';
import type { IContextualMenuProps } from './ContextualMenu.types';
/**
* ContextualMenu description
*/
export declare const ContextualMenu: React.FunctionComponent<IContextualMenuProps>;
@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenu = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var Utilities_1 = require("../../Utilities");
var ContextualMenu_base_1 = require("./ContextualMenu.base");
var ContextualMenu_styles_1 = require("./ContextualMenu.styles");
function onRenderSubMenu(subMenuProps) {
return React.createElement(LocalContextualMenu, tslib_1.__assign({}, subMenuProps));
}
// This is to prevent cyclic import with ContextualMenu.base.tsx.
var LocalContextualMenu = (0, Utilities_1.styled)(ContextualMenu_base_1.ContextualMenuBase, ContextualMenu_styles_1.getStyles, function (props) { return ({
onRenderSubMenu: props.onRenderSubMenu
? (0, Utilities_1.composeRenderFunction)(props.onRenderSubMenu, onRenderSubMenu)
: onRenderSubMenu,
}); }, { scope: 'ContextualMenu' });
/**
* ContextualMenu description
*/
exports.ContextualMenu = LocalContextualMenu;
exports.ContextualMenu.displayName = 'ContextualMenu';
//# sourceMappingURL=ContextualMenu.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ContextualMenu.js","sourceRoot":"../src/","sources":["components/ContextualMenu/ContextualMenu.tsx"],"names":[],"mappings":";;;;AAAA,6BAA+B;AAC/B,6CAAgE;AAChE,6DAA2D;AAC3D,iEAAoD;AAGpD,SAAS,eAAe,CAAC,YAAkC;IACzD,OAAO,oBAAC,mBAAmB,uBAAK,YAAY,EAAI,CAAC;AACnD,CAAC;AAED,iEAAiE;AACjE,IAAM,mBAAmB,GAAkD,IAAA,kBAAM,EAK/E,wCAAkB,EAClB,iCAAS,EACT,UAAC,KAA2B,IAAK,OAAA,CAAC;IAChC,eAAe,EAAE,KAAK,CAAC,eAAe;QACpC,CAAC,CAAC,IAAA,iCAAqB,EAAC,KAAK,CAAC,eAAe,EAAE,eAAe,CAAC;QAC/D,CAAC,CAAC,eAAe;CACpB,CAAC,EAJ+B,CAI/B,EACF,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAC5B,CAAC;AAEF;;GAEG;AACU,QAAA,cAAc,GAAkD,mBAAmB,CAAC;AACjG,sBAAc,CAAC,WAAW,GAAG,gBAAgB,CAAC","sourcesContent":["import * as React from 'react';\nimport { styled, composeRenderFunction } from '../../Utilities';\nimport { ContextualMenuBase } from './ContextualMenu.base';\nimport { getStyles } from './ContextualMenu.styles';\nimport type { IContextualMenuProps, IContextualMenuStyleProps, IContextualMenuStyles } from './ContextualMenu.types';\n\nfunction onRenderSubMenu(subMenuProps: IContextualMenuProps) {\n return <LocalContextualMenu {...subMenuProps} />;\n}\n\n// This is to prevent cyclic import with ContextualMenu.base.tsx.\nconst LocalContextualMenu: React.FunctionComponent<IContextualMenuProps> = styled<\n IContextualMenuProps,\n IContextualMenuStyleProps,\n IContextualMenuStyles\n>(\n ContextualMenuBase,\n getStyles,\n (props: IContextualMenuProps) => ({\n onRenderSubMenu: props.onRenderSubMenu\n ? composeRenderFunction(props.onRenderSubMenu, onRenderSubMenu)\n : onRenderSubMenu,\n }),\n { scope: 'ContextualMenu' },\n);\n\n/**\n * ContextualMenu description\n */\nexport const ContextualMenu: React.FunctionComponent<IContextualMenuProps> = LocalContextualMenu;\nContextualMenu.displayName = 'ContextualMenu';\n"]}
@@ -0,0 +1,2 @@
import type { IContextualMenuStyleProps, IContextualMenuStyles } from './ContextualMenu.types';
export declare const getStyles: (props: IContextualMenuStyleProps) => IContextualMenuStyles;
@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStyles = void 0;
var Styling_1 = require("../../Styling");
var ContextualMenu_cnstyles_1 = require("./ContextualMenu.cnstyles");
var GlobalClassNames = {
root: 'ms-ContextualMenu',
container: 'ms-ContextualMenu-container',
list: 'ms-ContextualMenu-list',
header: 'ms-ContextualMenu-header',
title: 'ms-ContextualMenu-title',
isopen: 'is-open',
};
var getStyles = function (props) {
var className = props.className, theme = props.theme;
var classNames = (0, Styling_1.getGlobalClassNames)(GlobalClassNames, theme);
var fonts = theme.fonts, semanticColors = theme.semanticColors, effects = theme.effects;
return {
root: [
theme.fonts.medium,
classNames.root,
classNames.isopen,
{
backgroundColor: semanticColors.menuBackground,
minWidth: '180px',
},
className,
],
container: [
classNames.container,
{
selectors: {
':focus': { outline: 0 },
},
},
],
list: [
classNames.list,
classNames.isopen,
{
listStyleType: 'none',
margin: '0',
padding: '0',
},
],
header: [
classNames.header,
fonts.small,
{
fontWeight: Styling_1.FontWeights.semibold,
color: semanticColors.menuHeader,
background: 'none',
backgroundColor: 'transparent',
border: 'none',
height: ContextualMenu_cnstyles_1.CONTEXTUAL_MENU_ITEM_HEIGHT,
lineHeight: ContextualMenu_cnstyles_1.CONTEXTUAL_MENU_ITEM_HEIGHT,
cursor: 'default',
padding: '0px 6px',
userSelect: 'none',
textAlign: 'left',
},
],
title: [
classNames.title,
{
fontSize: fonts.mediumPlus.fontSize,
paddingRight: '14px',
paddingLeft: '14px',
paddingBottom: '5px',
paddingTop: '5px',
backgroundColor: semanticColors.menuItemBackgroundPressed,
},
],
subComponentStyles: {
callout: {
root: {
boxShadow: effects.elevation8,
},
},
menuItem: {},
},
};
};
exports.getStyles = getStyles;
//# sourceMappingURL=ContextualMenu.styles.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ContextualMenu.styles.js","sourceRoot":"../src/","sources":["components/ContextualMenu/ContextualMenu.styles.ts"],"names":[],"mappings":";;;AAAA,yCAAiE;AACjE,qEAAwE;AAGxE,IAAM,gBAAgB,GAAG;IACvB,IAAI,EAAE,mBAAmB;IACzB,SAAS,EAAE,6BAA6B;IACxC,IAAI,EAAE,wBAAwB;IAC9B,MAAM,EAAE,0BAA0B;IAClC,KAAK,EAAE,yBAAyB;IAChC,MAAM,EAAE,SAAS;CAClB,CAAC;AAEK,IAAM,SAAS,GAAG,UAAC,KAAgC;IAChD,IAAA,SAAS,GAAY,KAAK,UAAjB,EAAE,KAAK,GAAK,KAAK,MAAV,CAAW;IACnC,IAAM,UAAU,GAAG,IAAA,6BAAmB,EAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAExD,IAAA,KAAK,GAA8B,KAAK,MAAnC,EAAE,cAAc,GAAc,KAAK,eAAnB,EAAE,OAAO,GAAK,KAAK,QAAV,CAAW;IAEjD,OAAO;QACL,IAAI,EAAE;YACJ,KAAK,CAAC,KAAK,CAAC,MAAM;YAClB,UAAU,CAAC,IAAI;YACf,UAAU,CAAC,MAAM;YACjB;gBACE,eAAe,EAAE,cAAc,CAAC,cAAc;gBAC9C,QAAQ,EAAE,OAAO;aAClB;YACD,SAAS;SACV;QACD,SAAS,EAAE;YACT,UAAU,CAAC,SAAS;YACpB;gBACE,SAAS,EAAE;oBACT,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;iBACzB;aACF;SACF;QACD,IAAI,EAAE;YACJ,UAAU,CAAC,IAAI;YACf,UAAU,CAAC,MAAM;YACjB;gBACE,aAAa,EAAE,MAAM;gBACrB,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,GAAG;aACb;SACF;QACD,MAAM,EAAE;YACN,UAAU,CAAC,MAAM;YACjB,KAAK,CAAC,KAAK;YACX;gBACE,UAAU,EAAE,qBAAW,CAAC,QAAQ;gBAChC,KAAK,EAAE,cAAc,CAAC,UAAU;gBAChC,UAAU,EAAE,MAAM;gBAClB,eAAe,EAAE,aAAa;gBAC9B,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,qDAA2B;gBACnC,UAAU,EAAE,qDAA2B;gBACvC,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,SAAS;gBAClB,UAAU,EAAE,MAAM;gBAClB,SAAS,EAAE,MAAM;aAClB;SACF;QACD,KAAK,EAAE;YACL,UAAU,CAAC,KAAK;YAChB;gBACE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ;gBACnC,YAAY,EAAE,MAAM;gBACpB,WAAW,EAAE,MAAM;gBACnB,aAAa,EAAE,KAAK;gBACpB,UAAU,EAAE,KAAK;gBACjB,eAAe,EAAE,cAAc,CAAC,yBAAyB;aAC1D;SACF;QACD,kBAAkB,EAAE;YAClB,OAAO,EAAE;gBACP,IAAI,EAAE;oBACJ,SAAS,EAAE,OAAO,CAAC,UAAU;iBAC9B;aACF;YACD,QAAQ,EAAE,EAAE;SACb;KACF,CAAC;AACJ,CAAC,CAAC;AAvEW,QAAA,SAAS,aAuEpB","sourcesContent":["import { getGlobalClassNames, FontWeights } from '../../Styling';\nimport { CONTEXTUAL_MENU_ITEM_HEIGHT } from './ContextualMenu.cnstyles';\nimport type { IContextualMenuStyleProps, IContextualMenuStyles } from './ContextualMenu.types';\n\nconst GlobalClassNames = {\n root: 'ms-ContextualMenu',\n container: 'ms-ContextualMenu-container',\n list: 'ms-ContextualMenu-list',\n header: 'ms-ContextualMenu-header',\n title: 'ms-ContextualMenu-title',\n isopen: 'is-open',\n};\n\nexport const getStyles = (props: IContextualMenuStyleProps): IContextualMenuStyles => {\n const { className, theme } = props;\n const classNames = getGlobalClassNames(GlobalClassNames, theme);\n\n const { fonts, semanticColors, effects } = theme;\n\n return {\n root: [\n theme.fonts.medium,\n classNames.root,\n classNames.isopen,\n {\n backgroundColor: semanticColors.menuBackground,\n minWidth: '180px',\n },\n className,\n ],\n container: [\n classNames.container,\n {\n selectors: {\n ':focus': { outline: 0 },\n },\n },\n ],\n list: [\n classNames.list,\n classNames.isopen,\n {\n listStyleType: 'none',\n margin: '0',\n padding: '0',\n },\n ],\n header: [\n classNames.header,\n fonts.small,\n {\n fontWeight: FontWeights.semibold,\n color: semanticColors.menuHeader,\n background: 'none',\n backgroundColor: 'transparent',\n border: 'none',\n height: CONTEXTUAL_MENU_ITEM_HEIGHT,\n lineHeight: CONTEXTUAL_MENU_ITEM_HEIGHT,\n cursor: 'default',\n padding: '0px 6px',\n userSelect: 'none',\n textAlign: 'left',\n },\n ],\n title: [\n classNames.title,\n {\n fontSize: fonts.mediumPlus.fontSize,\n paddingRight: '14px',\n paddingLeft: '14px',\n paddingBottom: '5px',\n paddingTop: '5px',\n backgroundColor: semanticColors.menuItemBackgroundPressed,\n },\n ],\n subComponentStyles: {\n callout: {\n root: {\n boxShadow: effects.elevation8,\n },\n },\n menuItem: {},\n },\n };\n};\n"]}
@@ -0,0 +1,579 @@
import * as React from 'react';
import { DirectionalHint } from '../../common/DirectionalHint';
import type { IFocusZoneProps } from '../../FocusZone';
import type { IIconProps } from '../../Icon';
import type { ICalloutProps, ICalloutContentStyleProps } from '../../Callout';
import type { ITheme, IStyle } from '../../Styling';
import type { IButtonStyles } from '../../Button';
import type { IRefObject, IBaseProps, IRectangle, IRenderFunction, IStyleFunctionOrObject, IComponentAs } from '../../Utilities';
import type { IWithResponsiveModeState } from '../../ResponsiveMode';
import type { IContextualMenuClassNames, IMenuItemClassNames } from './ContextualMenu.classNames';
import type { IVerticalDividerClassNames } from '../Divider/VerticalDivider.types';
import type { IContextualMenuItemProps, IContextualMenuRenderItem, IContextualMenuItemStyleProps, IContextualMenuItemRenderFunctions } from './ContextualMenuItem.types';
import type { IKeytipProps } from '../../Keytip';
import type { Target } from '@fluentui/react-hooks';
import type { IPopupRestoreFocusParams } from '../../Popup';
import { IContextualMenuItemWrapperProps } from './ContextualMenuItemWrapper/ContextualMenuItemWrapper.types';
export { DirectionalHint } from '../../common/DirectionalHint';
/**
* {@docCategory ContextualMenu}
*/
export declare enum ContextualMenuItemType {
Normal = 0,
Divider = 1,
Header = 2,
Section = 3
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenu {
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuProps extends IBaseProps<IContextualMenu>, React.RefAttributes<HTMLDivElement>, IWithResponsiveModeState {
/**
* Optional callback to access the IContextualMenu interface. Use this instead of ref for accessing
* the public methods and properties of the component.
* @deprecated ContextualMenu has no imperative methods, so componentRef no longer returns a ref
*/
componentRef?: IRefObject<IContextualMenu>;
/**
* Call to provide customized styling that will layer on top of the variant rules.
*/
styles?: IStyleFunctionOrObject<IContextualMenuStyleProps, IContextualMenuStyles>;
/**
* Theme provided by higher-order component.
*/
theme?: ITheme;
/**
* Additional CSS class to apply to the ContextualMenu.
*/
className?: string;
/**
* The target that the ContextualMenu should try to position itself based on.
* It can be either an element, a query selector string resolving to a valid element,
* or a MouseEvent. If a MouseEvent is given, the origin point of the event will be used.
*/
target?: Target;
/**
* How the menu should be positioned
* @defaultvalue DirectionalHint.bottomAutoEdge
*/
directionalHint?: DirectionalHint;
/**
* How the menu should be positioned in RTL layouts.
* If not specified, a mirror of `directionalHint` will be used.
*/
directionalHintForRTL?: DirectionalHint;
/**
* The gap between the ContextualMenu and the target
* @defaultvalue 0
*/
gapSpace?: number;
/**
* The width of the beak.
* @defaultvalue 16
*/
beakWidth?: number;
/**
* If true the context menu will render as the same width as the target element
* @defaultvalue false
*/
useTargetWidth?: boolean;
/**
* If true the context menu will have a minimum width equal to the width of the target element
* @defaultvalue false
*/
useTargetAsMinWidth?: boolean;
/**
* The bounding rectangle (or callback that returns a rectangle) which the contextual menu can appear in.
*/
bounds?: IRectangle | ((target?: Target, targetWindow?: Window) => IRectangle | undefined);
/**
* If true then the beak is visible. If false it will not be shown.
*/
isBeakVisible?: boolean;
/**
* If true, the menu will be positioned to cover the target.
* If false, it will be positioned next to the target.
* @defaultvalue false
*/
coverTarget?: boolean;
/**
* If true the positioning logic will prefer to flip edges rather than to nudge the rectangle to fit within bounds,
* thus making sure the element aligns perfectly with target's alignment edge
*/
alignTargetEdge?: boolean;
/**
* Menu items to display.
*/
items: IContextualMenuItem[];
/**
* Used as `aria-labelledby` for the menu element inside the callout.
*/
labelElementId?: string;
/**
* Whether to focus on the menu when mounted.
* @defaultvalue true
*/
shouldFocusOnMount?: boolean;
/**
* Whether to focus on the contextual menu container (as opposed to the first menu item).
*
* Avoid using as it breaks the default focus behaviour when using assistive technologies.
*/
shouldFocusOnContainer?: boolean;
/**
* Callback when the ContextualMenu tries to close. If `dismissAll` is true then all
* submenus will be dismissed.
*/
onDismiss?: (ev?: Event | React.MouseEvent | React.KeyboardEvent, dismissAll?: boolean) => void;
/**
* Click handler which is invoked if `onClick` is not passed for individual contextual
* menu item.
* Returning true will dismiss the menu even if `ev.preventDefault()` was called.
*/
onItemClick?: (ev?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>, item?: IContextualMenuItem) => boolean | void;
/**
* Whether this menu is a submenu of another menu.
*/
isSubMenu?: boolean;
/**
* ID for the ContextualMenu's root element (inside the callout).
* Should be used for `aria-owns` and other such uses, rather than direct reference for programmatic purposes.
*/
id?: string;
/**
* Accessible label for the ContextualMenu's root element (inside the callout).
*/
ariaLabel?: string;
/**
* If true do not render on a new layer. If false render on a new layer.
* @defaultvalue false
*/
doNotLayer?: boolean;
/**
* If true the position will not change sides in an attempt to fit the ContextualMenu within bounds.
* It will still attempt to align it to whatever bounds are given.
* @defaultvalue false
*/
directionalHintFixed?: boolean;
/**
* Callback for when the menu has been opened.
*/
onMenuOpened?: (contextualMenu?: IContextualMenuProps) => void;
/**
* Callback for when the menu is being closed (removing from the DOM).
*/
onMenuDismissed?: (contextualMenu?: IContextualMenuProps) => void;
/**
* Additional custom props for the Callout.
*/
calloutProps?: ICalloutProps;
/**
* Title to be displayed at the top of the menu, above the items.
*/
title?: string;
/**
* Method to provide the classnames to style the contextual menu.
* @deprecated Use `styles` instead to leverage mergeStyles API.
*/
getMenuClassNames?: (theme: ITheme, className?: string) => IContextualMenuClassNames;
/** Custom render function for a submenu. */
onRenderSubMenu?: IRenderFunction<IContextualMenuProps>;
/**
* Method to override the render of the list of menu items.
*/
onRenderMenuList?: IRenderFunction<IContextualMenuListProps>;
/**
* Method to wrap menu items. Gives the ability to wrap a custom
* tooltip to each menu item button.
*/
onRenderContextualMenuItem?: IRenderFunction<IContextualMenuItem>;
/**
* Delay (in milliseconds) to wait before expanding / dismissing a submenu on mouseEnter or mouseLeave
*/
subMenuHoverDelay?: number;
/**
* Custom component to use for rendering individual menu items.
* @defaultvalue ContextualMenuItem
*/
contextualMenuItemAs?: IComponentAs<IContextualMenuItemProps>;
/**
* Props to pass down to the FocusZone.
* NOTE: the default FocusZoneDirection will be used unless a direction
* is specified in the focusZoneProps (even if other focusZoneProps are defined)
* @defaultvalue \{ direction: FocusZoneDirection.vertical \}
*/
focusZoneProps?: IFocusZoneProps;
/**
* Custom component to use for rendering the focus zone (the root).
* @defaultValue FocusZone
*/
focusZoneAs?: IComponentAs<IFocusZoneProps>;
/**
* If true, renders the ContextualMenu in a hidden state.
* Use this flag, rather than rendering a ContextualMenu conditionally based on visibility,
* to improve rendering performance when it becomes visible.
* Note: When ContextualMenu is hidden its content will not be rendered. It will only render
* once the ContextualMenu is visible.
*/
hidden?: boolean;
/**
* If true, the menu will be updated even when `hidden=true`. Note that this will consume
* resources to update even when nothing is being shown to the user. This might be helpful if
* your updates are small and you want the menu to display quickly when `hidden` is set to false.
*/
shouldUpdateWhenHidden?: boolean;
/**
* If true, the contextual menu will not be updated until focus enters the menu via other means.
* This will only result in different behavior when `shouldFocusOnMount = false`.
*/
delayUpdateFocusOnHover?: boolean;
/**
* Called when the component is unmounting, and focus needs to be restored. If this is provided,
* focus will not be restored automatically, and you'll need to call `params.originalElement.focus()`.
*/
onRestoreFocus?: (params: IPopupRestoreFocusParams) => void;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuItemRenderProps extends IContextualMenuItem {
index: number;
focusableElementIndex: number;
totalItemCount: number;
hasCheckmarks: boolean;
hasIcons: boolean;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuListProps {
items: IContextualMenuItem[];
totalItemCount: number;
hasCheckmarks: boolean;
hasIcons: boolean;
defaultMenuItemRenderer: (item: IContextualMenuItemRenderProps) => React.ReactNode;
ariaLabel?: string;
labelElementId?: string;
role?: string;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuItem {
/**
* Optional callback to access the IContextualMenuRenderItem interface.
* This will get passed down to ContextualMenuItem.
*/
componentRef?: IRefObject<IContextualMenuRenderItem>;
/**
* Unique id to identify the item
*/
key: string;
/**
* Text of the menu item.
* If a standard hyphen (-) is passed in, then the item will be rendered as a divider.
* If a dash must appear as text, use an emdash (—), figuredash (), or minus symbol () instead.
*/
text?: string;
/**
* Secondary description for the menu item to display
*/
secondaryText?: string;
itemType?: ContextualMenuItemType;
/**
* Props for an icon to display next to the item.
*/
iconProps?: IIconProps;
/**
* Custom render function for the menu item icon.
* iconProps must be present on at least one item for onRenderIcon to be called.
*/
onRenderIcon?: IRenderFunction<IContextualMenuItemProps>;
/**
* Props for the Icon used for the chevron.
*/
submenuIconProps?: IIconProps;
/**
* Whether the menu item is disabled
* @defaultvalue false
*/
disabled?: boolean;
/**
* If the menu item is a split button, this prop disables purely the primary action of the button.
* @defaultvalue false
*/
primaryDisabled?: boolean;
/**
* @deprecated Not used
*/
shortCut?: string;
/**
* Whether or not this menu item can be checked
* @defaultvalue false
*/
canCheck?: boolean;
/**
* Whether or not this menu item is currently checked.
* @defaultvalue false
*/
checked?: boolean;
/**
* Whether or not this menu item is a splitButton.
* @defaultvalue false
*/
split?: boolean;
/**
* Any custom data the developer wishes to associate with the menu item.
*/
data?: any;
/**
* Callback for when the menu item is invoked. If `ev.preventDefault()` is called in `onClick`,
* the click will not close the menu.
*
* Only for ContextualMenu items, returning true will dismiss the menu even if `ev.preventDefault()`
* was called (does not apply for button or CommandBar sub-menu items).
*/
onClick?: (ev?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>, item?: IContextualMenuItem) => boolean | void;
/**
* Navigate to this URL when the menu item is clicked.
*/
href?: string;
/**
* Target window when using `href`.
*/
target?: string;
/**
* Link relation setting when using `href`.
* If `target` is `_blank`, `rel` is defaulted to a value to prevent clickjacking.
*/
rel?: string;
/**
* Properties to apply to a submenu to this item.
*
* The ContextualMenu will provide default values for `target`, `onDismiss`, `isSubMenu`,
* `id`, `shouldFocusOnMount`, `directionalHint`, `className`, and `gapSpace`, all of which
* can be overridden.
*/
subMenuProps?: IContextualMenuProps;
/**
* Method to provide the classnames to style the individual items inside a menu.
* @deprecated Use `styles` prop of `IContextualMenuItemProps` to leverage mergeStyles API.
*/
getItemClassNames?: (theme: ITheme, disabled: boolean, expanded: boolean, checked: boolean, isAnchorLink: boolean, knownIcon: boolean, itemClassName?: string, dividerClassName?: string, iconClassName?: string, subMenuClassName?: string, primaryDisabled?: boolean) => IMenuItemClassNames;
/**
* Optional IContextualMenuItemProps overrides to customize behaviors such as item styling via `styles`.
*/
itemProps?: Partial<IContextualMenuItemProps>;
/**
* Method to provide the classnames to style the Vertical Divider of a split button inside a menu.
* Default value is the `getSplitButtonVerticalDividerClassNames` func defined in `ContextualMenu.classnames.ts`.
* @defaultvalue getSplitButtonVerticalDividerClassNames
*/
getSplitButtonVerticalDividerClassNames?: (theme: ITheme) => IVerticalDividerClassNames;
/**
* Properties to apply to render this item as a section.
* This prop is mutually exclusive with `subMenuProps`.
*/
sectionProps?: IContextualMenuSection;
/**
* Additional CSS class to apply to the menu item.
*/
className?: string;
/**
* Additional styles to apply to the menu item
* @deprecated Use `styles` instead to leverage mergeStyles API.
*/
style?: React.CSSProperties;
/**
* Custom accessible label for the element.
* If no override is specified, the `aria-label` attribute will contain the item name.
*/
ariaLabel?: string;
/**
* Title (tooltip) text displayed when hovering over an item.
*/
title?: string;
/**
* Method to custom render this menu item.
* For keyboard accessibility, the top-level rendered item should be a focusable element
* (like an anchor or a button) or have the `data-is-focusable` property set to true.
*
* @param item - Item to render. Will typically be of type `IContextualMenuItem`.
* (When rendering a command bar item, will be `ICommandBarItemProps`.)
* @param dismissMenu - Function to dismiss the menu. Can be used to ensure that a custom menu
* item click dismisses the menu. (Will be undefined if rendering a command bar item.)
*/
onRender?: (item: any, dismissMenu: (ev?: any, dismissAll?: boolean) => void) => React.ReactNode;
/**
* An override for the child content of the contextual menu item.
*/
contextualMenuItemAs?: IComponentAs<IContextualMenuItemProps>;
/**
* An override for the entire component used to render the contextal menu item.
*/
contextualMenuItemWrapperAs?: IComponentAs<IContextualMenuItemWrapperProps>;
/**
* Method to customize sub-components rendering of this menu item.
*
* @param props - Props used to pass into render functions
* @param defaultRenders - Default render functions that renders default sub-components
*/
onRenderContent?: (props: IContextualMenuItemProps, defaultRenders: IContextualMenuItemRenderFunctions) => React.ReactNode;
/**
* A function to be executed on mouse down. This is executed before an `onClick` event and can
* be used to interrupt native on click events as well. The click event should still handle
* the commands. This should only be used in special cases when react and non-react are mixed.
*/
onMouseDown?: (item: IContextualMenuItem, event: React.MouseEvent<HTMLElement>) => void;
/**
* Optional override for the menu button's role.
* @default `menuitem` or `menuitemcheckbox`
*/
role?: string;
/**
* When rendering a custom menu component that is passed in, the component might also be a list of
* elements. We want to keep track of the correct index our menu is using based off of
* the length of the custom list. It is up to the user to increment the count for their list.
*/
customOnRenderListLength?: number;
/**
* Keytip for this contextual menu item
*/
keytipProps?: IKeytipProps;
/**
* @deprecated Use subMenuProps.items instead.
*/
items?: IContextualMenuItem[];
/**
* Any additional properties to use when custom rendering menu items.
*/
[propertyName: string]: any;
/**
* Detailed description of the menu item for the benefit of screen readers.
*/
ariaDescription?: string;
/**
* ID of the element that contains additional detailed descriptive information for screen readers
*/
ariaDescribedBy?: string;
/**
* @deprecated No longer used. All contextual menu items are now focusable when disabled.
*/
inactive?: boolean;
/**
* Text of the menu item.
* @deprecated Use `text` instead.
*/
name?: string;
/**
* Flag which indicates that, when the item is clicked, the 'target' for the click event should be
* overridden to reflect the launch target from the root menu.
* This avoids a situation where the 'target' of the event may wind up detached from the DOM
* when the menu is dismissed in response to the click.
*/
preferMenuTargetAsEventTarget?: boolean;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuSection extends React.ClassAttributes<any> {
/**
* The items to include inside the section.
*/
items: IContextualMenuItem[];
/**
* The optional section title.
*/
title?: string | IContextualMenuItem;
/**
* If set to true, the section will display a divider at the top of the section.
*/
topDivider?: boolean;
/**
* If set to true, the section will display a divider at the bottom of the section.
*/
bottomDivider?: boolean;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IMenuItemStyles extends IButtonStyles {
/**
* Styles for a menu item that is an anchor link.
*/
item?: IStyle;
/**
* Styles for the content inside the button/link of the menuItem.
*/
linkContent?: IStyle;
/**
* Styles for a menu item that is an anchor link.
*/
anchorLink?: IStyle;
/**
* Default icon color style for known icons.
*/
iconColor?: IStyle;
/**
* Default style for checkmark icons.
*/
checkmarkIcon?: IStyle;
/**
* Styles for the submenu icon of a menu item.
*/
subMenuIcon?: IStyle;
/**
* Styles for a divider item of a ContextualMenu.
*/
divider?: IStyle;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuStyleProps {
theme: ITheme;
className?: string;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuStyles {
/**
* Style override for the contextual menu title.
*/
title: IStyle;
/**
* Style for the container which parents all menu items.
*/
container: IStyle;
/**
* Base styles for the root element of all ContextualMenus.
*/
root: IStyle;
/**
* Styles for the header item of a ContextualMenu
*/
header: IStyle;
/**
* Styles for the list that contains all menuItems.
*/
list: IStyle;
/**
* SubComponent styles.
*/
subComponentStyles: IContextualMenuSubComponentStyles;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuSubComponentStyles {
/** Styles for the callout that hosts the ContextualMenu options. */
callout: IStyleFunctionOrObject<ICalloutContentStyleProps, any>;
/** Styles for each menu item. */
menuItem: IStyleFunctionOrObject<IContextualMenuItemStyleProps, any>;
}
@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuItemType = exports.DirectionalHint = void 0;
var DirectionalHint_1 = require("../../common/DirectionalHint");
Object.defineProperty(exports, "DirectionalHint", { enumerable: true, get: function () { return DirectionalHint_1.DirectionalHint; } });
/**
* {@docCategory ContextualMenu}
*/
var ContextualMenuItemType;
(function (ContextualMenuItemType) {
ContextualMenuItemType[ContextualMenuItemType["Normal"] = 0] = "Normal";
ContextualMenuItemType[ContextualMenuItemType["Divider"] = 1] = "Divider";
ContextualMenuItemType[ContextualMenuItemType["Header"] = 2] = "Header";
ContextualMenuItemType[ContextualMenuItemType["Section"] = 3] = "Section";
})(ContextualMenuItemType || (exports.ContextualMenuItemType = ContextualMenuItemType = {}));
//# sourceMappingURL=ContextualMenu.types.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
import * as React from 'react';
import type { IContextualMenuItemProps } from './ContextualMenuItem.types';
import type { JSXElement } from '@fluentui/utilities';
export declare class ContextualMenuItemBase extends React.Component<IContextualMenuItemProps, {}> {
constructor(props: IContextualMenuItemProps);
render(): JSXElement;
openSubMenu: () => void;
dismissSubMenu: () => void;
dismissMenu: (dismissAll?: boolean) => void;
private _renderLayout;
}
@@ -0,0 +1,109 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuItemBase = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var index_1 = require("../../utilities/contextualMenu/index");
var Utilities_1 = require("../../Utilities");
var Icon_1 = require("../../Icon");
var defaultIconRenderer = function (props) {
var item = props.item, classNames = props.classNames;
var iconProps = item.iconProps;
return React.createElement(Icon_1.Icon, tslib_1.__assign({}, iconProps, { className: classNames.icon }));
};
var renderItemIcon = function (props) {
var item = props.item, hasIcons = props.hasIcons;
if (!hasIcons) {
return null;
}
if (item.onRenderIcon) {
return item.onRenderIcon(props, defaultIconRenderer);
}
return defaultIconRenderer(props);
};
var renderCheckMarkIcon = function (_a) {
var onCheckmarkClick = _a.onCheckmarkClick, item = _a.item, classNames = _a.classNames;
var isItemChecked = (0, index_1.getIsChecked)(item);
if (onCheckmarkClick) {
// Ensures that the item is passed as the first argument to the checkmark click callback.
var onClick = function (e) { return onCheckmarkClick(item, e); };
return (React.createElement(Icon_1.Icon, { iconName: item.canCheck !== false && isItemChecked ? 'CheckMark' : '', className: classNames.checkmarkIcon,
// eslint-disable-next-line react/jsx-no-bind
onClick: onClick }));
}
return null;
};
var renderItemName = function (_a) {
var item = _a.item, classNames = _a.classNames;
/* eslint-disable @typescript-eslint/no-deprecated */
if (item.text || item.name) {
return React.createElement("span", { className: classNames.label }, item.text || item.name);
}
/* eslint-enable @typescript-eslint/no-deprecated */
return null;
};
var renderSecondaryText = function (_a) {
var item = _a.item, classNames = _a.classNames;
if (item.secondaryText) {
return React.createElement("span", { className: classNames.secondaryText }, item.secondaryText);
}
return null;
};
var renderSubMenuIcon = function (_a) {
var item = _a.item, classNames = _a.classNames, theme = _a.theme;
if ((0, index_1.hasSubmenu)(item)) {
return (React.createElement(Icon_1.Icon, tslib_1.__assign({ iconName: (0, Utilities_1.getRTL)(theme) ? 'ChevronLeft' : 'ChevronRight' }, item.submenuIconProps, { className: classNames.subMenuIcon })));
}
return null;
};
var ContextualMenuItemBase = /** @class */ (function (_super) {
tslib_1.__extends(ContextualMenuItemBase, _super);
function ContextualMenuItemBase(props) {
var _this = _super.call(this, props) || this;
_this.openSubMenu = function () {
var _a = _this.props, item = _a.item, openSubMenu = _a.openSubMenu, getSubmenuTarget = _a.getSubmenuTarget;
if (getSubmenuTarget) {
var submenuTarget = getSubmenuTarget();
if ((0, index_1.hasSubmenu)(item) && openSubMenu && submenuTarget) {
openSubMenu(item, submenuTarget);
}
}
};
_this.dismissSubMenu = function () {
var _a = _this.props, item = _a.item, dismissSubMenu = _a.dismissSubMenu;
if ((0, index_1.hasSubmenu)(item) && dismissSubMenu) {
dismissSubMenu();
}
};
_this.dismissMenu = function (dismissAll) {
var dismissMenu = _this.props.dismissMenu;
if (dismissMenu) {
dismissMenu(undefined /* ev */, dismissAll);
}
};
(0, Utilities_1.initializeComponentRef)(_this);
return _this;
}
ContextualMenuItemBase.prototype.render = function () {
var _a = this.props, item = _a.item, classNames = _a.classNames;
var renderContent = item.onRenderContent || this._renderLayout;
return (React.createElement("div", { className: item.split ? classNames.linkContentMenu : classNames.linkContent }, renderContent(this.props, {
renderCheckMarkIcon: renderCheckMarkIcon,
renderItemIcon: renderItemIcon,
renderItemName: renderItemName,
renderSecondaryText: renderSecondaryText,
renderSubMenuIcon: renderSubMenuIcon,
})));
};
ContextualMenuItemBase.prototype._renderLayout = function (props, defaultRenders) {
return (React.createElement(React.Fragment, null,
defaultRenders.renderCheckMarkIcon(props),
defaultRenders.renderItemIcon(props),
defaultRenders.renderItemName(props),
defaultRenders.renderSecondaryText(props),
defaultRenders.renderSubMenuIcon(props)));
};
return ContextualMenuItemBase;
}(React.Component));
exports.ContextualMenuItemBase = ContextualMenuItemBase;
//# sourceMappingURL=ContextualMenuItem.base.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
import * as React from 'react';
import type { IContextualMenuItemProps } from './ContextualMenuItem.types';
/**
* ContextualMenuItem description
*/
export declare const ContextualMenuItem: React.FunctionComponent<IContextualMenuItemProps>;
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuItem = void 0;
var Utilities_1 = require("../../Utilities");
var ContextualMenuItem_base_1 = require("./ContextualMenuItem.base");
var ContextualMenu_classNames_1 = require("./ContextualMenu.classNames");
/**
* ContextualMenuItem description
*/
exports.ContextualMenuItem = (0, Utilities_1.styled)(ContextualMenuItem_base_1.ContextualMenuItemBase, ContextualMenu_classNames_1.getItemStyles, undefined, { scope: 'ContextualMenuItem' });
//# sourceMappingURL=ContextualMenuItem.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ContextualMenuItem.js","sourceRoot":"../src/","sources":["components/ContextualMenu/ContextualMenuItem.ts"],"names":[],"mappings":";;;AACA,6CAAyC;AACzC,qEAAmE;AACnE,yEAA4D;AAO5D;;GAEG;AACU,QAAA,kBAAkB,GAAsD,IAAA,kBAAM,EAIzF,gDAAsB,EAAE,yCAAa,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC","sourcesContent":["import * as React from 'react';\nimport { styled } from '../../Utilities';\nimport { ContextualMenuItemBase } from './ContextualMenuItem.base';\nimport { getItemStyles } from './ContextualMenu.classNames';\nimport type {\n IContextualMenuItemProps,\n IContextualMenuItemStyleProps,\n IContextualMenuItemStyles,\n} from './ContextualMenuItem.types';\n\n/**\n * ContextualMenuItem description\n */\nexport const ContextualMenuItem: React.FunctionComponent<IContextualMenuItemProps> = styled<\n IContextualMenuItemProps,\n IContextualMenuItemStyleProps,\n IContextualMenuItemStyles\n>(ContextualMenuItemBase, getItemStyles, undefined, { scope: 'ContextualMenuItem' });\n"]}
@@ -0,0 +1,228 @@
import * as React from 'react';
import type { IContextualMenuItem } from './ContextualMenu.types';
import type { IMenuItemClassNames } from './ContextualMenu.classNames';
import type { IStyle, ITheme } from '../../Styling';
import type { IRefObject, IStyleFunctionOrObject } from '../../Utilities';
import type { IButtonStyles } from '../../Button';
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuRenderItem {
/**
* Function to open this item's subMenu, if present.
*/
openSubMenu: () => void;
/**
* Function to close this item's subMenu, if present.
*/
dismissSubMenu: () => void;
/**
* Dismiss the menu this item belongs to.
*/
dismissMenu: (dismissAll?: boolean) => void;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuItemProps extends React.HTMLAttributes<IContextualMenuItemProps> {
/**
* Optional callback to access the IContextualMenuRenderItem interface. Use this instead of ref for accessing
* the public methods and properties of the component.
*/
componentRef?: IRefObject<IContextualMenuRenderItem>;
/**
* Call to provide customized styling that will layer on top of the variant rules.
*/
styles?: IStyleFunctionOrObject<IContextualMenuItemStyleProps, IContextualMenuItemStyles>;
/**
* Theme provided by High-Order Component.
*/
theme?: ITheme;
/**
* Additional css class to apply to the ContextualMenuItem
* @defaultvalue undefined
*/
className?: string;
/**
* The item to display
*/
item: IContextualMenuItem;
/**
* Classnames for different aspects of a menu item
*/
classNames: IMenuItemClassNames;
/**
* Index of the item
*/
index: number;
/**
* If this item has icons
*/
hasIcons: boolean | undefined;
/**
* Click handler for the checkmark
*/
onCheckmarkClick?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>) => void;
/**
* This prop will get set by ContextualMenu and can be called to open this item's subMenu, if present.
*/
openSubMenu?: (item: any, target: HTMLElement) => void;
/**
* This prop will get set by ContextualMenu and can be called to close this item's subMenu, if present.
*/
dismissSubMenu?: () => void;
/**
* This prop will get set by ContextualMenu and can be called to close the menu this item belongs to.
* If dismissAll is true, all menus will be closed.
*/
dismissMenu?: (ev?: any, dismissAll?: boolean) => void;
/**
* This prop will get set by the wrapping component and will return the element that wraps this ContextualMenuItem.
* Used for openSubMenu.
*/
getSubmenuTarget?: () => HTMLElement | undefined;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuItemStyleProps {
/**
* Theme provided by High-Order Component.
*/
theme: ITheme;
/**
* Accept custom classNames
*/
className?: string;
/**
* Whether or not the menu item is disabled.
*/
disabled: boolean;
/**
* Whether or not the menu item is expanded.
*/
expanded: boolean;
/**
* Whether or not the menu item is checked.
*/
checked: boolean;
/**
* Indicates if a menu item is an anchor link.
*/
isAnchorLink: boolean;
/**
* Indicates if the icon used is of the known set of icons.
*/
knownIcon: boolean;
/**
* The optional class name to apply to the item element.
*/
itemClassName?: string;
/**
* The optional class name to apply to the divider element.
*/
dividerClassName?: string;
/**
* The optional class name to apply to the icon element.
*/
iconClassName?: string;
/**
* The optional class name to apply to the sub-menu if present.
*/
subMenuClassName?: string;
/**
* Whether or not the primary section of a split menu item is disabled.
*/
primaryDisabled?: boolean;
}
/**
* {@docCategory ContextualMenu}
*/
export interface IContextualMenuItemStyles extends IButtonStyles {
/**
* Style for the root element.
*/
root?: IStyle;
/**
* Styles for a menu item that is an anchor link.
*/
item?: IStyle;
/**
* Styles for a divider item of a ContextualMenu.
*/
divider?: IStyle;
/**
* Styles for the content inside the button/link of the menuItem.
*/
linkContent?: IStyle;
/**
* Styles for a menu item that is an anchor link.
*/
anchorLink?: IStyle;
/**
* Styles for the icon element of a menu item.
*/
icon?: IStyle;
/**
* Default icon color style for known icons.
*/
iconColor?: IStyle;
/**
* Default style for checkmark icons.
*/
checkmarkIcon?: IStyle;
/**
* Styles for the submenu icon of a menu item.
*/
subMenuIcon?: IStyle;
/**
* Styles for the label of a menu item.
*/
label?: IStyle;
/**
* Styles for the secondary text of a menu item.
*/
secondaryText?: IStyle;
/**
* Styles for the container of a split menu item.
*/
splitContainer?: IStyle;
/**
* Styles for the primary portion of a split menu item.
*/
splitPrimary?: IStyle;
/**
* Styles for the menu portion of a split menu item.
*/
splitMenu?: IStyle;
/**
* Styles for a menu item that is a link.
*/
linkContentMenu?: IStyle;
/**
* Styles for hidden screen reader text.
*/
screenReaderText?: IStyle;
}
export interface IContextualMenuItemRenderFunctions {
/**
* Rendering function for check mark icon
*/
renderCheckMarkIcon: (props: IContextualMenuItemProps, customClassNames?: string[]) => React.ReactNode;
/**
* Rendering function for item icon
*/
renderItemIcon: (props: IContextualMenuItemProps, customClassNames?: string[]) => React.ReactNode;
/**
* Rendering function for item label
*/
renderItemName: (props: IContextualMenuItemProps, customClassNames?: string[]) => React.ReactNode;
/**
* Rendering function for secondary text label
*/
renderSecondaryText: (props: IContextualMenuItemProps, customClassNames?: string[]) => React.ReactNode;
/**
* Rendering function for submenu icon
*/
renderSubMenuIcon: (props: IContextualMenuItemProps, customClassNames?: string[]) => React.ReactNode;
}
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=ContextualMenuItem.types.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,12 @@
import * as React from 'react';
import { ContextualMenuItemWrapper } from './ContextualMenuItemWrapper';
import type { JSXElement } from '@fluentui/utilities';
export declare class ContextualMenuAnchor extends ContextualMenuItemWrapper {
private _anchor;
private _ariaDescriptionId;
private _getMemoizedMenuButtonKeytipProps;
render(): JSXElement;
protected _getSubmenuTarget: () => HTMLElement | undefined;
protected _onItemClick: (ev: React.MouseEvent<HTMLElement>) => void;
protected _renderAriaDescription: (ariaDescription?: string, className?: string) => JSXElement | null;
}
@@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuAnchor = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var Utilities_1 = require("../../../Utilities");
var ContextualMenuItemWrapper_1 = require("./ContextualMenuItemWrapper");
var KeytipData_1 = require("../../../KeytipData");
var index_1 = require("../../../utilities/contextualMenu/index");
var ContextualMenuItem_1 = require("../ContextualMenuItem");
var ContextualMenuAnchor = /** @class */ (function (_super) {
tslib_1.__extends(ContextualMenuAnchor, _super);
function ContextualMenuAnchor() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._anchor = React.createRef();
_this._getMemoizedMenuButtonKeytipProps = (0, Utilities_1.memoizeFunction)(function (keytipProps) {
return tslib_1.__assign(tslib_1.__assign({}, keytipProps), { hasMenu: true });
});
_this._getSubmenuTarget = function () {
return _this._anchor.current ? _this._anchor.current : undefined;
};
_this._onItemClick = function (ev) {
var _a = _this.props, item = _a.item, onItemClick = _a.onItemClick;
if (onItemClick) {
onItemClick(item, ev);
}
};
_this._renderAriaDescription = function (ariaDescription, className) {
// If ariaDescription is given, descriptionId will be assigned to ariaDescriptionSpan
return ariaDescription ? (React.createElement("span", { id: _this._ariaDescriptionId, className: className }, ariaDescription)) : null;
};
return _this;
}
ContextualMenuAnchor.prototype.render = function () {
var _this = this;
var _a = this.props, item = _a.item, classNames = _a.classNames, index = _a.index, focusableElementIndex = _a.focusableElementIndex, totalItemCount = _a.totalItemCount, hasCheckmarks = _a.hasCheckmarks, hasIcons = _a.hasIcons, expandedMenuItemKey = _a.expandedMenuItemKey, onItemClick = _a.onItemClick, openSubMenu = _a.openSubMenu, dismissSubMenu = _a.dismissSubMenu, dismissMenu = _a.dismissMenu;
var ChildrenRenderer = ContextualMenuItem_1.ContextualMenuItem;
if (this.props.item.contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(this.props.item.contextualMenuItemAs, ChildrenRenderer);
}
if (this.props.contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(this.props.contextualMenuItemAs, ChildrenRenderer);
}
var anchorRel = item.rel;
if (item.target && item.target.toLowerCase() === '_blank') {
anchorRel = anchorRel ? anchorRel : 'nofollow noopener noreferrer'; // Safe default to prevent tabjacking
}
var itemHasSubmenu = (0, index_1.hasSubmenu)(item);
var nativeProps = (0, Utilities_1.getNativeProps)(item, Utilities_1.anchorProperties);
var disabled = (0, index_1.isItemDisabled)(item);
var itemProps = item.itemProps, ariaDescription = item.ariaDescription;
var keytipProps = item.keytipProps;
if (keytipProps && itemHasSubmenu) {
keytipProps = this._getMemoizedMenuButtonKeytipProps(keytipProps);
}
// Check for ariaDescription to set the _ariaDescriptionId and render a hidden span with
// the description in it to be added to ariaDescribedBy
if (ariaDescription) {
this._ariaDescriptionId = (0, Utilities_1.getId)();
}
var ariaDescribedByIds = (0, Utilities_1.mergeAriaAttributeValues)(item.ariaDescribedBy, ariaDescription ? this._ariaDescriptionId : undefined, nativeProps['aria-describedby']);
var additionalItemProperties = {
'aria-describedby': ariaDescribedByIds,
};
return (React.createElement("div", null,
React.createElement(KeytipData_1.KeytipData, { keytipProps: item.keytipProps, ariaDescribedBy: ariaDescribedByIds, disabled: disabled }, function (keytipAttributes) { return (React.createElement("a", tslib_1.__assign({}, additionalItemProperties, nativeProps, keytipAttributes, { ref: _this._anchor, href: item.href, target: item.target, rel: anchorRel, className: classNames.root, role: "menuitem", "aria-haspopup": itemHasSubmenu || undefined, "aria-expanded": itemHasSubmenu ? item.key === expandedMenuItemKey : undefined, "aria-posinset": focusableElementIndex + 1, "aria-setsize": totalItemCount, "aria-disabled": (0, index_1.isItemDisabled)(item),
// eslint-disable-next-line @typescript-eslint/no-deprecated
style: item.style, onClick: _this._onItemClick, onMouseEnter: _this._onItemMouseEnter, onMouseLeave: _this._onItemMouseLeave, onMouseMove: _this._onItemMouseMove, onKeyDown: itemHasSubmenu ? _this._onItemKeyDown : undefined }),
React.createElement(ChildrenRenderer, tslib_1.__assign({ componentRef: item.componentRef, item: item, classNames: classNames, index: index, onCheckmarkClick: hasCheckmarks && onItemClick ? onItemClick : undefined, hasIcons: hasIcons, openSubMenu: openSubMenu, dismissSubMenu: dismissSubMenu, dismissMenu: dismissMenu, getSubmenuTarget: _this._getSubmenuTarget }, itemProps)),
_this._renderAriaDescription(ariaDescription, classNames.screenReaderText))); })));
};
return ContextualMenuAnchor;
}(ContextualMenuItemWrapper_1.ContextualMenuItemWrapper));
exports.ContextualMenuAnchor = ContextualMenuAnchor;
//# sourceMappingURL=ContextualMenuAnchor.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
import { ContextualMenuItemWrapper } from './ContextualMenuItemWrapper';
import type { JSXElement } from '@fluentui/utilities';
export declare class ContextualMenuButton extends ContextualMenuItemWrapper {
private _btn;
private _ariaDescriptionId;
private _getMemoizedMenuButtonKeytipProps;
render(): JSXElement;
protected _renderAriaDescription: (ariaDescription?: string, className?: string) => JSXElement | null;
protected _getSubmenuTarget: () => HTMLElement | undefined;
}
@@ -0,0 +1,89 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuButton = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var Utilities_1 = require("../../../Utilities");
var ContextualMenuItemWrapper_1 = require("./ContextualMenuItemWrapper");
var KeytipData_1 = require("../../../KeytipData");
var index_1 = require("../../../utilities/contextualMenu/index");
var ContextualMenuItem_1 = require("../ContextualMenuItem");
var ContextualMenuButton = /** @class */ (function (_super) {
tslib_1.__extends(ContextualMenuButton, _super);
function ContextualMenuButton() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._btn = React.createRef();
_this._getMemoizedMenuButtonKeytipProps = (0, Utilities_1.memoizeFunction)(function (keytipProps) {
return tslib_1.__assign(tslib_1.__assign({}, keytipProps), { hasMenu: true });
});
_this._renderAriaDescription = function (ariaDescription, className) {
// If ariaDescription is given, descriptionId will be assigned to ariaDescriptionSpan
return ariaDescription ? (React.createElement("span", { id: _this._ariaDescriptionId, className: className }, ariaDescription)) : null;
};
_this._getSubmenuTarget = function () {
return _this._btn.current ? _this._btn.current : undefined;
};
return _this;
}
ContextualMenuButton.prototype.render = function () {
var _this = this;
var _a = this.props, item = _a.item, classNames = _a.classNames, index = _a.index, focusableElementIndex = _a.focusableElementIndex, totalItemCount = _a.totalItemCount, hasCheckmarks = _a.hasCheckmarks, hasIcons = _a.hasIcons, contextualMenuItemAs = _a.contextualMenuItemAs, expandedMenuItemKey = _a.expandedMenuItemKey, onItemMouseDown = _a.onItemMouseDown, onItemClick = _a.onItemClick, openSubMenu = _a.openSubMenu, dismissSubMenu = _a.dismissSubMenu, dismissMenu = _a.dismissMenu;
var ChildrenRenderer = ContextualMenuItem_1.ContextualMenuItem;
if (item.contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(item.contextualMenuItemAs, ChildrenRenderer);
}
if (contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(contextualMenuItemAs, ChildrenRenderer);
}
var isChecked = (0, index_1.getIsChecked)(item);
var canCheck = isChecked !== null;
var defaultRole = (0, index_1.getMenuItemAriaRole)(item);
var itemHasSubmenu = (0, index_1.hasSubmenu)(item);
var itemProps = item.itemProps, ariaLabel = item.ariaLabel, ariaDescription = item.ariaDescription;
var buttonNativeProperties = (0, Utilities_1.getNativeProps)(item, Utilities_1.buttonProperties);
// Do not add the disabled attribute to the button so that it is focusable
delete buttonNativeProperties.disabled;
var itemRole = item.role || defaultRole;
// Check for ariaDescription to set the _ariaDescriptionId and render a hidden span with
// the description in it to be added to ariaDescribedBy
if (ariaDescription) {
this._ariaDescriptionId = (0, Utilities_1.getId)();
}
var ariaDescribedByIds = (0, Utilities_1.mergeAriaAttributeValues)(item.ariaDescribedBy, ariaDescription ? this._ariaDescriptionId : undefined, buttonNativeProperties['aria-describedby']);
var itemButtonProperties = {
className: classNames.root,
onClick: this._onItemClick,
onKeyDown: itemHasSubmenu ? this._onItemKeyDown : undefined,
onMouseEnter: this._onItemMouseEnter,
onMouseLeave: this._onItemMouseLeave,
onMouseDown: function (ev) {
return onItemMouseDown ? onItemMouseDown(item, ev) : undefined;
},
onMouseMove: this._onItemMouseMove,
href: item.href,
title: item.title,
'aria-label': ariaLabel,
'aria-describedby': ariaDescribedByIds,
'aria-haspopup': itemHasSubmenu || undefined,
'aria-expanded': itemHasSubmenu ? item.key === expandedMenuItemKey : undefined,
'aria-posinset': focusableElementIndex + 1,
'aria-setsize': totalItemCount,
'aria-disabled': (0, index_1.isItemDisabled)(item),
'aria-checked': (itemRole === 'menuitemcheckbox' || itemRole === 'menuitemradio') && canCheck ? !!isChecked : undefined,
'aria-selected': itemRole === 'menuitem' && canCheck ? !!isChecked : undefined,
role: itemRole,
// eslint-disable-next-line @typescript-eslint/no-deprecated
style: item.style,
};
var keytipProps = item.keytipProps;
if (keytipProps && itemHasSubmenu) {
keytipProps = this._getMemoizedMenuButtonKeytipProps(keytipProps);
}
return (React.createElement(KeytipData_1.KeytipData, { keytipProps: keytipProps, ariaDescribedBy: ariaDescribedByIds, disabled: (0, index_1.isItemDisabled)(item) }, function (keytipAttributes) { return (React.createElement("button", tslib_1.__assign({ ref: _this._btn }, buttonNativeProperties, itemButtonProperties, keytipAttributes),
React.createElement(ChildrenRenderer, tslib_1.__assign({ componentRef: item.componentRef, item: item, classNames: classNames, index: index, onCheckmarkClick: hasCheckmarks && onItemClick ? onItemClick : undefined, hasIcons: hasIcons, openSubMenu: openSubMenu, dismissSubMenu: dismissSubMenu, dismissMenu: dismissMenu, getSubmenuTarget: _this._getSubmenuTarget }, itemProps)),
_this._renderAriaDescription(ariaDescription, classNames.screenReaderText))); }));
};
return ContextualMenuButton;
}(ContextualMenuItemWrapper_1.ContextualMenuItemWrapper));
exports.ContextualMenuButton = ContextualMenuButton;
//# sourceMappingURL=ContextualMenuButton.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,12 @@
import * as React from 'react';
import type { IContextualMenuItemWrapperProps } from './ContextualMenuItemWrapper.types';
export declare class ContextualMenuItemWrapper extends React.Component<IContextualMenuItemWrapperProps> {
constructor(props: IContextualMenuItemWrapperProps);
shouldComponentUpdate(newProps: IContextualMenuItemWrapperProps): boolean;
protected _onItemMouseEnter: (ev: React.MouseEvent<HTMLElement>) => void;
protected _onItemClick: (ev: React.MouseEvent<HTMLElement>) => void;
protected _onItemMouseLeave: (ev: React.MouseEvent<HTMLElement>) => void;
protected _onItemKeyDown: (ev: React.KeyboardEvent<HTMLElement>) => void;
protected _onItemMouseMove: (ev: React.MouseEvent<HTMLElement>) => void;
protected _getSubmenuTarget: () => HTMLElement | undefined;
}
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuItemWrapper = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var Utilities_1 = require("../../../Utilities");
var ContextualMenuItemWrapper = /** @class */ (function (_super) {
tslib_1.__extends(ContextualMenuItemWrapper, _super);
function ContextualMenuItemWrapper(props) {
var _this = _super.call(this, props) || this;
_this._onItemMouseEnter = function (ev) {
var _a = _this.props, item = _a.item, onItemMouseEnter = _a.onItemMouseEnter;
if (onItemMouseEnter) {
onItemMouseEnter(item, ev, ev.currentTarget);
}
};
_this._onItemClick = function (ev) {
var _a = _this.props, item = _a.item, onItemClickBase = _a.onItemClickBase;
if (onItemClickBase) {
onItemClickBase(item, ev, ev.currentTarget);
}
};
_this._onItemMouseLeave = function (ev) {
var _a = _this.props, item = _a.item, onItemMouseLeave = _a.onItemMouseLeave;
if (onItemMouseLeave) {
onItemMouseLeave(item, ev);
}
};
_this._onItemKeyDown = function (ev) {
var _a = _this.props, item = _a.item, onItemKeyDown = _a.onItemKeyDown;
if (onItemKeyDown) {
onItemKeyDown(item, ev);
}
};
_this._onItemMouseMove = function (ev) {
var _a = _this.props, item = _a.item, onItemMouseMove = _a.onItemMouseMove;
if (onItemMouseMove) {
onItemMouseMove(item, ev, ev.currentTarget);
}
};
_this._getSubmenuTarget = function () {
return undefined;
};
(0, Utilities_1.initializeComponentRef)(_this);
return _this;
}
ContextualMenuItemWrapper.prototype.shouldComponentUpdate = function (newProps) {
return !(0, Utilities_1.shallowCompare)(newProps, this.props);
};
return ContextualMenuItemWrapper;
}(React.Component));
exports.ContextualMenuItemWrapper = ContextualMenuItemWrapper;
//# sourceMappingURL=ContextualMenuItemWrapper.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ContextualMenuItemWrapper.js","sourceRoot":"../src/","sources":["components/ContextualMenu/ContextualMenuItemWrapper/ContextualMenuItemWrapper.tsx"],"names":[],"mappings":";;;;AAAA,6BAA+B;AAC/B,gDAA4E;AAG5E;IAA+C,qDAAgD;IAC7F,mCAAY,KAAsC;QAChD,YAAA,MAAK,YAAC,KAAK,CAAC,SAAC;QAQL,uBAAiB,GAAG,UAAC,EAAiC;YACxD,IAAA,KAA6B,KAAI,CAAC,KAAK,EAArC,IAAI,UAAA,EAAE,gBAAgB,sBAAe,CAAC;YAC9C,IAAI,gBAAgB,EAAE,CAAC;gBACrB,gBAAgB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,aAA4B,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC,CAAC;QAEQ,kBAAY,GAAG,UAAC,EAAiC;YACnD,IAAA,KAA4B,KAAI,CAAC,KAAK,EAApC,IAAI,UAAA,EAAE,eAAe,qBAAe,CAAC;YAC7C,IAAI,eAAe,EAAE,CAAC;gBACpB,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,aAA4B,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC,CAAC;QAEQ,uBAAiB,GAAG,UAAC,EAAiC;YACxD,IAAA,KAA6B,KAAI,CAAC,KAAK,EAArC,IAAI,UAAA,EAAE,gBAAgB,sBAAe,CAAC;YAC9C,IAAI,gBAAgB,EAAE,CAAC;gBACrB,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC;QAEQ,oBAAc,GAAG,UAAC,EAAoC;YACxD,IAAA,KAA0B,KAAI,CAAC,KAAK,EAAlC,IAAI,UAAA,EAAE,aAAa,mBAAe,CAAC;YAC3C,IAAI,aAAa,EAAE,CAAC;gBAClB,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC;QAEQ,sBAAgB,GAAG,UAAC,EAAiC;YACvD,IAAA,KAA4B,KAAI,CAAC,KAAK,EAApC,IAAI,UAAA,EAAE,eAAe,qBAAe,CAAC;YAC7C,IAAI,eAAe,EAAE,CAAC;gBACpB,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,aAA4B,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC,CAAC;QAEQ,uBAAiB,GAAG;YAC5B,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC;QA5CA,IAAA,kCAAsB,EAAC,KAAI,CAAC,CAAC;;IAC/B,CAAC;IAEM,yDAAqB,GAA5B,UAA6B,QAAyC;QACpE,OAAO,CAAC,IAAA,0BAAc,EAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAwCH,gCAAC;AAAD,CAAC,AAhDD,CAA+C,KAAK,CAAC,SAAS,GAgD7D;AAhDY,8DAAyB","sourcesContent":["import * as React from 'react';\nimport { initializeComponentRef, shallowCompare } from '../../../Utilities';\nimport type { IContextualMenuItemWrapperProps } from './ContextualMenuItemWrapper.types';\n\nexport class ContextualMenuItemWrapper extends React.Component<IContextualMenuItemWrapperProps> {\n constructor(props: IContextualMenuItemWrapperProps) {\n super(props);\n initializeComponentRef(this);\n }\n\n public shouldComponentUpdate(newProps: IContextualMenuItemWrapperProps): boolean {\n return !shallowCompare(newProps, this.props);\n }\n\n protected _onItemMouseEnter = (ev: React.MouseEvent<HTMLElement>): void => {\n const { item, onItemMouseEnter } = this.props;\n if (onItemMouseEnter) {\n onItemMouseEnter(item, ev, ev.currentTarget as HTMLElement);\n }\n };\n\n protected _onItemClick = (ev: React.MouseEvent<HTMLElement>): void => {\n const { item, onItemClickBase } = this.props;\n if (onItemClickBase) {\n onItemClickBase(item, ev, ev.currentTarget as HTMLElement);\n }\n };\n\n protected _onItemMouseLeave = (ev: React.MouseEvent<HTMLElement>): void => {\n const { item, onItemMouseLeave } = this.props;\n if (onItemMouseLeave) {\n onItemMouseLeave(item, ev);\n }\n };\n\n protected _onItemKeyDown = (ev: React.KeyboardEvent<HTMLElement>): void => {\n const { item, onItemKeyDown } = this.props;\n if (onItemKeyDown) {\n onItemKeyDown(item, ev);\n }\n };\n\n protected _onItemMouseMove = (ev: React.MouseEvent<HTMLElement>): void => {\n const { item, onItemMouseMove } = this.props;\n if (onItemMouseMove) {\n onItemMouseMove(item, ev, ev.currentTarget as HTMLElement);\n }\n };\n\n protected _getSubmenuTarget = (): HTMLElement | undefined => {\n return undefined;\n };\n}\n"]}
@@ -0,0 +1,104 @@
import * as React from 'react';
import { ContextualMenuItemWrapper } from './ContextualMenuItemWrapper';
import type { IContextualMenuItem, IContextualMenuItemProps } from '../../../ContextualMenu';
import type { IMenuItemClassNames } from '../ContextualMenu.classNames';
import type { IComponentAs, IRefObject } from '../../../Utilities';
export interface IContextualMenuItemWrapperProps extends React.ClassAttributes<IContextualMenuItem> {
/**
* Optional callback to access the ContextualMenuSplitButton interface. Use this instead of ref for accessing
* the public methods and properties of the component.
*/
componentRef?: IRefObject<ContextualMenuItemWrapper>;
/**
* The IContextualMenuItem that is used to render the item in the menu.
*/
item: IContextualMenuItem;
/**
* CSS class to apply to the context menu.
*/
classNames: IMenuItemClassNames;
/**
* The index number of the wrapper among all items in the contextual menu including things like dividers and headers.
*/
index: number;
/**
* The index number of the wrapper among all items in the contextual menu excluding dividers and headers.
*/
focusableElementIndex: number;
/**
* The total number of items in the contextual menu.
*/
totalItemCount: number;
/**
* Whether or not if the item for the wrapper uses checkmarks.
*/
hasCheckmarks?: boolean;
/**
* Whether or not the item for the wrapper uses icons.
*/
hasIcons?: boolean;
/**
* Method to override the render of the individual menu items.
* @defaultvalue ContextualMenuItem
*/
contextualMenuItemAs?: IComponentAs<IContextualMenuItemProps>;
/**
* Callback for when the user's mouse enters the wrapper.
*/
onItemMouseEnter?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>, target: HTMLElement) => boolean | void;
/**
* Callback for when the user's mouse leaves the wrapper.
*/
onItemMouseLeave?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>) => void;
/**
* Callback for when the user's mouse moves in the wrapper.
*/
onItemMouseMove?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>, target: HTMLElement) => void;
/**
* Callback for the mousedown event on the icon button in the wrapper.
*/
onItemMouseDown?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>) => void;
/**
* Callback for when the click event on the primary button.
*/
executeItemClick?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) => void;
/**
* Callback for when the click event on the icon button from the wrapper.
*/
onItemClick?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) => void;
/**
* Callback for when the click event on the icon button which also takes in a specific HTMLElement
* that will be focused.
*/
onItemClickBase?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>, target: HTMLElement) => void;
/**
* Callback for keyboard events on the wrapper.
*/
onItemKeyDown?: (item: IContextualMenuItem, ev: React.KeyboardEvent<HTMLElement>) => void;
/**
* Callback to get the subMenu ID for an IContextualMenuItem.
* @deprecated ID relationship between a menu button and menu isn't necessary
*/
getSubMenuId?: (item: IContextualMenuItem) => string | undefined;
/**
* Key of the currently expanded subMenu.
*/
expandedMenuItemKey?: string;
/**
* Callback for touch/pointer events on the split button.
*/
onTap?: (ev: React.TouchEvent<HTMLElement> | PointerEvent) => void;
/**
* This prop will get set by ContextualMenu and can be called to open this item's subMenu, if present.
*/
openSubMenu?: (item: any, target: HTMLElement) => void;
/**
* This prop will get set by ContextualMenu and can be called to close this item's subMenu, if present.
*/
dismissSubMenu?: () => void;
/**
* This prop will get set by ContextualMenu and can be called to close the menu this item belongs to.
* If dismissAll is true, all menus will be closed.
*/
dismissMenu?: (ev?: any, dismissAll?: boolean) => void;
}
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=ContextualMenuItemWrapper.types.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ContextualMenuItemWrapper.types.js","sourceRoot":"../src/","sources":["components/ContextualMenu/ContextualMenuItemWrapper/ContextualMenuItemWrapper.types.ts"],"names":[],"mappings":"","sourcesContent":["import * as React from 'react';\nimport { ContextualMenuItemWrapper } from './ContextualMenuItemWrapper';\nimport type { IContextualMenuItem, IContextualMenuItemProps } from '../../../ContextualMenu';\nimport type { IMenuItemClassNames } from '../ContextualMenu.classNames';\nimport type { IComponentAs, IRefObject } from '../../../Utilities';\n\nexport interface IContextualMenuItemWrapperProps extends React.ClassAttributes<IContextualMenuItem> {\n /**\n * Optional callback to access the ContextualMenuSplitButton interface. Use this instead of ref for accessing\n * the public methods and properties of the component.\n */\n componentRef?: IRefObject<ContextualMenuItemWrapper>;\n\n /**\n * The IContextualMenuItem that is used to render the item in the menu.\n */\n item: IContextualMenuItem;\n\n /**\n * CSS class to apply to the context menu.\n */\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n classNames: IMenuItemClassNames;\n\n /**\n * The index number of the wrapper among all items in the contextual menu including things like dividers and headers.\n */\n index: number;\n\n /**\n * The index number of the wrapper among all items in the contextual menu excluding dividers and headers.\n */\n focusableElementIndex: number;\n\n /**\n * The total number of items in the contextual menu.\n */\n totalItemCount: number;\n\n /**\n * Whether or not if the item for the wrapper uses checkmarks.\n */\n hasCheckmarks?: boolean;\n\n /**\n * Whether or not the item for the wrapper uses icons.\n */\n hasIcons?: boolean;\n\n /**\n * Method to override the render of the individual menu items.\n * @defaultvalue ContextualMenuItem\n */\n contextualMenuItemAs?: IComponentAs<IContextualMenuItemProps>;\n\n /**\n * Callback for when the user's mouse enters the wrapper.\n */\n onItemMouseEnter?: (\n item: IContextualMenuItem,\n ev: React.MouseEvent<HTMLElement>,\n target: HTMLElement,\n ) => boolean | void;\n\n /**\n * Callback for when the user's mouse leaves the wrapper.\n */\n onItemMouseLeave?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>) => void;\n\n /**\n * Callback for when the user's mouse moves in the wrapper.\n */\n onItemMouseMove?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>, target: HTMLElement) => void;\n\n /**\n * Callback for the mousedown event on the icon button in the wrapper.\n */\n onItemMouseDown?: (item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>) => void;\n\n /**\n * Callback for when the click event on the primary button.\n */\n executeItemClick?: (\n item: IContextualMenuItem,\n ev: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n ) => void;\n\n /**\n * Callback for when the click event on the icon button from the wrapper.\n */\n onItemClick?: (\n item: IContextualMenuItem,\n ev: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n ) => void;\n\n /**\n * Callback for when the click event on the icon button which also takes in a specific HTMLElement\n * that will be focused.\n */\n onItemClickBase?: (\n item: IContextualMenuItem,\n ev: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,\n target: HTMLElement,\n ) => void;\n\n /**\n * Callback for keyboard events on the wrapper.\n */\n onItemKeyDown?: (item: IContextualMenuItem, ev: React.KeyboardEvent<HTMLElement>) => void;\n\n /**\n * Callback to get the subMenu ID for an IContextualMenuItem.\n * @deprecated ID relationship between a menu button and menu isn't necessary\n */\n getSubMenuId?: (item: IContextualMenuItem) => string | undefined;\n\n /**\n * Key of the currently expanded subMenu.\n */\n expandedMenuItemKey?: string;\n\n /**\n * Callback for touch/pointer events on the split button.\n */\n onTap?: (ev: React.TouchEvent<HTMLElement> | PointerEvent) => void;\n\n /**\n * This prop will get set by ContextualMenu and can be called to open this item's subMenu, if present.\n */\n openSubMenu?: (item: any, target: HTMLElement) => void;\n\n /**\n * This prop will get set by ContextualMenu and can be called to close this item's subMenu, if present.\n */\n dismissSubMenu?: () => void;\n\n /**\n * This prop will get set by ContextualMenu and can be called to close the menu this item belongs to.\n * If dismissAll is true, all menus will be closed.\n */\n dismissMenu?: (ev?: any, dismissAll?: boolean) => void;\n}\n"]}
@@ -0,0 +1,35 @@
import * as React from 'react';
import { ContextualMenuItemWrapper } from './ContextualMenuItemWrapper';
import type { IContextualMenuItemWrapperProps } from './ContextualMenuItemWrapper.types';
import type { JSXElement } from '@fluentui/utilities';
export interface IContextualMenuSplitButtonState {
}
export declare class ContextualMenuSplitButton extends ContextualMenuItemWrapper {
private _splitButton;
private _lastTouchTimeoutId;
private _processingTouch;
private _ariaDescriptionId;
private _dismissLabelId;
private _async;
private _events;
private _getMemoizedMenuButtonKeytipProps;
constructor(props: IContextualMenuItemWrapperProps);
componentDidMount(): void;
componentWillUnmount(): void;
render(): JSXElement | null;
protected _onItemKeyDown: (ev: React.KeyboardEvent<HTMLElement>) => void;
protected _getSubmenuTarget: () => HTMLElement | undefined;
protected _renderAriaDescription: (ariaDescription?: string, className?: string) => JSXElement | null;
private _renderSplitPrimaryButton;
private _renderSplitDivider;
private _renderSplitIconButton;
private _onItemMouseEnterPrimary;
private _onItemMouseEnterIcon;
private _onItemMouseMovePrimary;
private _onItemMouseMoveIcon;
private _onIconItemClick;
private _executeItemClick;
private _onTouchStart;
private _onPointerDown;
private _handleTouchAndPointerEvent;
}
@@ -0,0 +1,222 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextualMenuSplitButton = void 0;
var tslib_1 = require("tslib");
var React = require("react");
var Utilities_1 = require("../../../Utilities");
var ContextualMenuItem_1 = require("../ContextualMenuItem");
var ContextualMenu_classNames_1 = require("../ContextualMenu.classNames");
var KeytipData_1 = require("../../../KeytipData");
var index_1 = require("../../../utilities/contextualMenu/index");
var Divider_1 = require("../../../Divider");
var ContextualMenuItemWrapper_1 = require("./ContextualMenuItemWrapper");
var TouchIdleDelay = 500; /* ms */
var ContextualMenuSplitButton = /** @class */ (function (_super) {
tslib_1.__extends(ContextualMenuSplitButton, _super);
function ContextualMenuSplitButton(props) {
var _this = _super.call(this, props) || this;
_this._getMemoizedMenuButtonKeytipProps = (0, Utilities_1.memoizeFunction)(function (keytipProps) {
return tslib_1.__assign(tslib_1.__assign({}, keytipProps), { hasMenu: true });
});
_this._onItemKeyDown = function (ev) {
var _a = _this.props, item = _a.item, onItemKeyDown = _a.onItemKeyDown;
// eslint-disable-next-line @typescript-eslint/no-deprecated
if (ev.which === Utilities_1.KeyCodes.enter) {
_this._executeItemClick(ev);
ev.preventDefault();
ev.stopPropagation();
}
else if (onItemKeyDown) {
onItemKeyDown(item, ev);
}
};
_this._getSubmenuTarget = function () {
return _this._splitButton;
};
_this._renderAriaDescription = function (ariaDescription, className) {
// If ariaDescription is given, descriptionId will be assigned to ariaDescriptionSpan
return ariaDescription ? (React.createElement("span", { id: _this._ariaDescriptionId, className: className }, ariaDescription)) : null;
};
_this._onItemMouseEnterPrimary = function (ev) {
var _a = _this.props, item = _a.item, onItemMouseEnter = _a.onItemMouseEnter;
if (onItemMouseEnter) {
onItemMouseEnter(tslib_1.__assign(tslib_1.__assign({}, item), { subMenuProps: undefined, items: undefined }), ev, _this._splitButton);
}
};
_this._onItemMouseEnterIcon = function (ev) {
var _a = _this.props, item = _a.item, onItemMouseEnter = _a.onItemMouseEnter;
if (onItemMouseEnter) {
onItemMouseEnter(item, ev, _this._splitButton);
}
};
_this._onItemMouseMovePrimary = function (ev) {
var _a = _this.props, item = _a.item, onItemMouseMove = _a.onItemMouseMove;
if (onItemMouseMove) {
onItemMouseMove(tslib_1.__assign(tslib_1.__assign({}, item), { subMenuProps: undefined, items: undefined }), ev, _this._splitButton);
}
};
_this._onItemMouseMoveIcon = function (ev) {
var _a = _this.props, item = _a.item, onItemMouseMove = _a.onItemMouseMove;
if (onItemMouseMove) {
onItemMouseMove(item, ev, _this._splitButton);
}
};
_this._onIconItemClick = function (ev) {
var _a = _this.props, item = _a.item, onItemClickBase = _a.onItemClickBase;
if (onItemClickBase) {
onItemClickBase(item, ev, (_this._splitButton ? _this._splitButton : ev.currentTarget));
}
};
_this._executeItemClick = function (ev) {
var _a = _this.props, item = _a.item, executeItemClick = _a.executeItemClick, onItemClick = _a.onItemClick;
if (item.disabled || item.isDisabled) {
return;
}
if (_this._processingTouch && !item.canCheck && onItemClick) {
return onItemClick(item, ev);
}
if (executeItemClick) {
executeItemClick(item, ev);
}
};
_this._onTouchStart = function (ev) {
if (_this._splitButton && !('onpointerdown' in _this._splitButton)) {
_this._handleTouchAndPointerEvent(ev);
}
};
_this._onPointerDown = function (ev) {
if (ev.pointerType === 'touch') {
_this._handleTouchAndPointerEvent(ev);
ev.preventDefault();
ev.stopImmediatePropagation();
}
};
_this._async = new Utilities_1.Async(_this);
_this._events = new Utilities_1.EventGroup(_this);
_this._dismissLabelId = (0, Utilities_1.getId)();
return _this;
}
ContextualMenuSplitButton.prototype.componentDidMount = function () {
if (this._splitButton && 'onpointerdown' in this._splitButton) {
this._events.on(this._splitButton, 'pointerdown', this._onPointerDown, true);
}
};
ContextualMenuSplitButton.prototype.componentWillUnmount = function () {
this._async.dispose();
this._events.dispose();
};
ContextualMenuSplitButton.prototype.render = function () {
var _this = this;
var _a;
var _b = this.props, item = _b.item, classNames = _b.classNames, index = _b.index, focusableElementIndex = _b.focusableElementIndex, totalItemCount = _b.totalItemCount, hasCheckmarks = _b.hasCheckmarks, hasIcons = _b.hasIcons, onItemMouseLeave = _b.onItemMouseLeave, expandedMenuItemKey = _b.expandedMenuItemKey;
var itemHasSubmenu = (0, index_1.hasSubmenu)(item);
var keytipProps = item.keytipProps;
if (keytipProps) {
keytipProps = this._getMemoizedMenuButtonKeytipProps(keytipProps);
}
// Check for ariaDescription to set the _ariaDescriptionId and render a hidden span with
// the description in it to be added to ariaDescribedBy
var ariaDescription = item.ariaDescription;
if (ariaDescription) {
this._ariaDescriptionId = (0, Utilities_1.getId)();
}
var ariaChecked = (_a = (0, index_1.getIsChecked)(item)) !== null && _a !== void 0 ? _a : undefined;
return (React.createElement(KeytipData_1.KeytipData, { keytipProps: keytipProps, disabled: (0, index_1.isItemDisabled)(item) }, function (keytipAttributes) { return (React.createElement("div", { "data-ktp-target": keytipAttributes['data-ktp-target'], ref: function (splitButton) {
_this._splitButton = splitButton;
}, role: (0, index_1.getMenuItemAriaRole)(item), "aria-label": item.ariaLabel, className: classNames.splitContainer, "aria-disabled": (0, index_1.isItemDisabled)(item), "aria-expanded": itemHasSubmenu ? item.key === expandedMenuItemKey : undefined, "aria-haspopup": true, "aria-describedby": (0, Utilities_1.mergeAriaAttributeValues)(item.ariaDescribedBy, ariaDescription ? _this._ariaDescriptionId : undefined, keytipAttributes['aria-describedby']), "aria-checked": ariaChecked, "aria-posinset": focusableElementIndex + 1, "aria-setsize": totalItemCount, onMouseEnter: _this._onItemMouseEnterPrimary, onMouseLeave: onItemMouseLeave ? onItemMouseLeave.bind(_this, tslib_1.__assign(tslib_1.__assign({}, item), { subMenuProps: null, items: null })) : undefined, onMouseMove: _this._onItemMouseMovePrimary, onKeyDown: _this._onItemKeyDown, onClick: _this._executeItemClick, onTouchStart: _this._onTouchStart, tabIndex: 0, "data-is-focusable": true, "aria-roledescription": item['aria-roledescription'] },
_this._renderSplitPrimaryButton(item, classNames, index, hasCheckmarks, hasIcons),
_this._renderSplitDivider(item),
_this._renderSplitIconButton(item, classNames, index, keytipAttributes),
_this._renderAriaDescription(ariaDescription, classNames.screenReaderText))); }));
};
ContextualMenuSplitButton.prototype._renderSplitPrimaryButton = function (item,
// eslint-disable-next-line @typescript-eslint/no-deprecated
classNames, index, hasCheckmarks, hasIcons) {
var _a = this.props, _b = _a.contextualMenuItemAs, ChildrenRenderer = _b === void 0 ? ContextualMenuItem_1.ContextualMenuItem : _b, onItemClick = _a.onItemClick;
var itemProps = {
key: item.key,
disabled: (0, index_1.isItemDisabled)(item) || item.primaryDisabled,
/* eslint-disable @typescript-eslint/no-deprecated */
name: item.name,
text: item.text || item.name,
secondaryText: item.secondaryText,
/* eslint-enable @typescript-eslint/no-deprecated */
className: classNames.splitPrimary,
canCheck: item.canCheck,
isChecked: item.isChecked,
checked: item.checked,
iconProps: item.iconProps,
id: this._dismissLabelId,
onRenderIcon: item.onRenderIcon,
data: item.data,
'data-is-focusable': false,
};
var itemComponentProps = item.itemProps;
return (React.createElement("button", tslib_1.__assign({}, (0, Utilities_1.getNativeProps)(itemProps, Utilities_1.buttonProperties)),
React.createElement(ChildrenRenderer, tslib_1.__assign({ "data-is-focusable": false, item: tslib_1.__assign(tslib_1.__assign({}, itemProps), { onClick: item.onClick }), classNames: classNames, index: index, onCheckmarkClick: hasCheckmarks && onItemClick ? onItemClick : undefined, hasIcons: hasIcons }, itemComponentProps))));
};
ContextualMenuSplitButton.prototype._renderSplitDivider = function (item) {
var getDividerClassNames = item.getSplitButtonVerticalDividerClassNames || ContextualMenu_classNames_1.getSplitButtonVerticalDividerClassNames;
return (React.createElement(Divider_1.VerticalDivider
// eslint-disable-next-line @typescript-eslint/no-deprecated
, {
// eslint-disable-next-line @typescript-eslint/no-deprecated
getClassNames: getDividerClassNames }));
};
ContextualMenuSplitButton.prototype._renderSplitIconButton = function (item, classNames, // eslint-disable-line @typescript-eslint/no-deprecated
index, keytipAttributes) {
var _a = this.props, onItemMouseLeave = _a.onItemMouseLeave, onItemMouseDown = _a.onItemMouseDown, openSubMenu = _a.openSubMenu, dismissSubMenu = _a.dismissSubMenu, dismissMenu = _a.dismissMenu;
var ChildrenRenderer = ContextualMenuItem_1.ContextualMenuItem;
if (this.props.item.contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(this.props.item.contextualMenuItemAs, ChildrenRenderer);
}
if (this.props.contextualMenuItemAs) {
ChildrenRenderer = (0, Utilities_1.composeComponentAs)(this.props.contextualMenuItemAs, ChildrenRenderer);
}
var itemProps = {
onClick: this._onIconItemClick,
disabled: (0, index_1.isItemDisabled)(item),
className: classNames.splitMenu,
subMenuProps: item.subMenuProps,
submenuIconProps: item.submenuIconProps,
split: true,
key: item.key,
'aria-labelledby': this._dismissLabelId,
};
var buttonProps = tslib_1.__assign(tslib_1.__assign({}, (0, Utilities_1.getNativeProps)(itemProps, Utilities_1.buttonProperties)), {
onMouseEnter: this._onItemMouseEnterIcon,
onMouseLeave: onItemMouseLeave ? onItemMouseLeave.bind(this, item) : undefined,
onMouseDown: function (ev) {
return onItemMouseDown ? onItemMouseDown(item, ev) : undefined;
},
onMouseMove: this._onItemMouseMoveIcon,
'data-is-focusable': false,
'data-ktp-execute-target': keytipAttributes['data-ktp-execute-target'],
'aria-haspopup': true,
});
var itemComponentProps = item.itemProps;
return (React.createElement("button", tslib_1.__assign({}, buttonProps),
React.createElement(ChildrenRenderer, tslib_1.__assign({ componentRef: item.componentRef, item: itemProps, classNames: classNames, index: index, hasIcons: false, openSubMenu: openSubMenu, dismissSubMenu: dismissSubMenu, dismissMenu: dismissMenu, getSubmenuTarget: this._getSubmenuTarget }, itemComponentProps))));
};
ContextualMenuSplitButton.prototype._handleTouchAndPointerEvent = function (ev) {
var _this = this;
var onTap = this.props.onTap;
if (onTap) {
onTap(ev);
}
// If we already have an existing timeout from a previous touch/pointer event
// cancel that timeout so we can set a new one.
if (this._lastTouchTimeoutId) {
this._async.clearTimeout(this._lastTouchTimeoutId);
this._lastTouchTimeoutId = undefined;
}
this._processingTouch = true;
this._lastTouchTimeoutId = this._async.setTimeout(function () {
_this._processingTouch = false;
_this._lastTouchTimeoutId = undefined;
}, TouchIdleDelay);
};
return ContextualMenuSplitButton;
}(ContextualMenuItemWrapper_1.ContextualMenuItemWrapper));
exports.ContextualMenuSplitButton = ContextualMenuSplitButton;
//# sourceMappingURL=ContextualMenuSplitButton.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
export * from './ContextualMenuAnchor';
export * from './ContextualMenuButton';
export * from './ContextualMenuSplitButton';
export * from './ContextualMenuItemWrapper';
export * from './ContextualMenuItemWrapper.types';
@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./ContextualMenuAnchor"), exports);
tslib_1.__exportStar(require("./ContextualMenuButton"), exports);
tslib_1.__exportStar(require("./ContextualMenuSplitButton"), exports);
tslib_1.__exportStar(require("./ContextualMenuItemWrapper"), exports);
tslib_1.__exportStar(require("./ContextualMenuItemWrapper.types"), exports);
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["components/ContextualMenu/ContextualMenuItemWrapper/index.ts"],"names":[],"mappings":";;;AAAA,iEAAuC;AACvC,iEAAuC;AACvC,sEAA4C;AAC5C,sEAA4C;AAC5C,4EAAkD","sourcesContent":["export * from './ContextualMenuAnchor';\nexport * from './ContextualMenuButton';\nexport * from './ContextualMenuSplitButton';\nexport * from './ContextualMenuItemWrapper';\nexport * from './ContextualMenuItemWrapper.types';\n"]}
@@ -0,0 +1,9 @@
export * from './ContextualMenu';
export * from './ContextualMenu.base';
export * from './ContextualMenu.types';
export * from './ContextualMenuItem';
export * from './ContextualMenuItem.base';
export * from './ContextualMenuItem.types';
export { getMenuItemStyles } from './ContextualMenu.cnstyles';
export { getItemClassNames as getContextualMenuItemClassNames, getItemStyles as getContextualMenuItemStyles, } from './ContextualMenu.classNames';
export type { IContextualMenuClassNames, IMenuItemClassNames, } from './ContextualMenu.classNames';
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getContextualMenuItemStyles = exports.getContextualMenuItemClassNames = exports.getMenuItemStyles = void 0;
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./ContextualMenu"), exports);
tslib_1.__exportStar(require("./ContextualMenu.base"), exports);
tslib_1.__exportStar(require("./ContextualMenu.types"), exports);
tslib_1.__exportStar(require("./ContextualMenuItem"), exports);
tslib_1.__exportStar(require("./ContextualMenuItem.base"), exports);
tslib_1.__exportStar(require("./ContextualMenuItem.types"), exports);
var ContextualMenu_cnstyles_1 = require("./ContextualMenu.cnstyles");
Object.defineProperty(exports, "getMenuItemStyles", { enumerable: true, get: function () { return ContextualMenu_cnstyles_1.getMenuItemStyles; } });
var ContextualMenu_classNames_1 = require("./ContextualMenu.classNames");
// eslint-disable-next-line @typescript-eslint/no-deprecated
Object.defineProperty(exports, "getContextualMenuItemClassNames", { enumerable: true, get: function () { return ContextualMenu_classNames_1.getItemClassNames; } });
Object.defineProperty(exports, "getContextualMenuItemStyles", { enumerable: true, get: function () { return ContextualMenu_classNames_1.getItemStyles; } });
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["components/ContextualMenu/index.ts"],"names":[],"mappings":";;;;AAAA,2DAAiC;AACjC,gEAAsC;AACtC,iEAAuC;AACvC,+DAAqC;AACrC,oEAA0C;AAC1C,qEAA2C;AAC3C,qEAA8D;AAArD,4HAAA,iBAAiB,OAAA;AAC1B,yEAIqC;AAHnC,4DAA4D;AAC5D,4IAAA,iBAAiB,OAAmC;AACpD,wIAAA,aAAa,OAA+B","sourcesContent":["export * from './ContextualMenu';\nexport * from './ContextualMenu.base';\nexport * from './ContextualMenu.types';\nexport * from './ContextualMenuItem';\nexport * from './ContextualMenuItem.base';\nexport * from './ContextualMenuItem.types';\nexport { getMenuItemStyles } from './ContextualMenu.cnstyles';\nexport {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n getItemClassNames as getContextualMenuItemClassNames,\n getItemStyles as getContextualMenuItemStyles,\n} from './ContextualMenu.classNames';\n\nexport type {\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n IContextualMenuClassNames,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n IMenuItemClassNames,\n} from './ContextualMenu.classNames';\n"]}