@progress/kendo-react-layout
Version:
React Layout components enable you to create a perceptive and intuitive layout of web projects. KendoReact Layout package
208 lines (207 loc) • 8.54 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import * as m from "react";
import i from "prop-types";
import { Keys as h, classNames as f, dispatchEvent as v } from "@progress/kendo-react-common";
import { EMPTY_ID as r, getItemById as a, getDirectParentId as b, getRootParentId as g, isIdEmptyOrZeroLevel as l, ZERO_LEVEL_ZERO_ITEM_ID as c } from "../utils/itemsIdsUtils.mjs";
import { prepareInputItemsForInternalWork as R } from "../utils/prepareInputItemsForInternalWork.mjs";
import { getNewItemIdUponKeyboardNavigation as I } from "../utils/getNewItemIdUponKeyboardNavigation.mjs";
import { getHoverOpenDelay as D, getHoverCloseDelay as H } from "../utils/hoverDelay.mjs";
import { MenuItemInternalsList as O } from "./MenuItemInternal.mjs";
import { DirectionHolder as C } from "../utils/DirectionHolder.mjs";
import { MouseOverHandler as y } from "../utils/MouseOverHandler.mjs";
const p = {
focusedItemId: r,
hoveredItemId: r,
tabbableItemId: c
}, n = class n extends m.Component {
constructor(t) {
super(t), this.menuWrapperEl = null, this.directionHolder = new C(), this.inputItems = [], this.items = [], this.reset = () => {
this.clearItemHoverAndLeaveRequestsIfApplicable(), this.setState(p);
}, this.onKeyDown = (e) => {
if (this.state.focusedItemId !== r) {
const s = a(this.state.focusedItemId, this.items);
let o = I(
this.items,
s.id,
e.keyCode,
e.key,
this.props.vertical,
this.directionHolder.getIsDirectionRightToLeft()
);
const d = a(o, this.items);
d && d.separator && (o = I(
this.items,
o,
e.keyCode,
e.key,
this.props.vertical,
this.directionHolder.getIsDirectionRightToLeft()
)), s.id !== o && (e.preventDefault(), this.setFocusedItemId(o)), (e.keyCode === h.enter || e.keyCode === h.space) && !s.disabled && (this.mouseOverHandler.handleItemSelectedViaKeyboard(), this.dispatchSelectEventIfWired(e, s.id), !e.isDefaultPrevented() && s.items.length === 0 && s.url && window.location.assign(s.url));
}
e.keyCode === h.esc && this.props.onClose && this.props.onClose.call(void 0, e);
}, this.onItemMouseOver = (e) => {
this.mouseOverHandler.IsMouseOverEnabled && (this.clearItemHoverAndLeaveRequestsIfApplicable(), this.itemHoverRequest = window.setTimeout(() => {
this.setHoveredItemId(e), this.itemHoverRequest = null;
}, D(this.props)));
}, this.onItemMouseLeave = (e) => {
this.mouseOverHandler.IsMouseOverEnabled && this.isItemWithDefaultClose(e) && (this.clearItemHoverAndLeaveRequestsIfApplicable(), this.itemLeaveRequest = window.setTimeout(() => {
this.setHoveredItemId(r), this.itemLeaveRequest = null;
}, H(this.props)));
}, this.onItemMouseDown = () => {
this.mouseOverHandler.handleItemMouseDown();
}, this.onItemFocus = (e) => {
this.setFocusedItemId(e), this.mouseOverHandler.handleItemFocus();
}, this.onItemClick = (e, s) => {
const o = a(s, this.items);
o.disabled || (this.setFocusedItemId(s), this.mouseOverHandler.handleItemClick(s, this.isItemWithDefaultClose(s)), this.dispatchSelectEventIfWired(e, s), !e.isDefaultPrevented() && o.url && window.location.assign(o.url));
}, this.onItemBlur = (e, s) => {
if (this.isItemWithDefaultClose(e) && this.setFocusedItemId(r), s.relatedTarget && s.relatedTarget.nodeName === "LI") {
const o = s.relatedTarget.getAttribute("id");
if (o && o.includes(this.menuItemId))
return;
}
this.props.onClose && this.props.onClose.call(void 0, s);
}, this.getInputItem = (e) => a(e, this.inputItems), this.mouseOverHandler = new y(this.props.openOnClick, this.reset, this.onItemMouseOver), this.state = Object.assign({}, p, { isFirstRender: !0 });
}
get menuItemId() {
return this.props.id;
}
get element() {
return this.menuWrapperEl;
}
get animate() {
return this.props.animate !== void 0 ? this.props.animate : n.defaultProps.animate;
}
/**
* @hidden
*/
render() {
this.prepareItems(), this.state.isFirstRender || this.directionHolder.setIsDirectionRightToLeft(this.checkIsDirectionRightToLeft());
const t = this.state.hoveredItemId ? this.state.hoveredItemId : this.state.focusedItemId ? b(this.state.focusedItemId) : r;
return /* @__PURE__ */ m.createElement(
"div",
{
id: this.props.id,
onKeyDown: this.onKeyDown,
style: this.props.style,
className: this.directionHolder.getIsDirectionRightToLeft() ? "k-rtl" : void 0,
ref: (e) => {
this.menuWrapperEl = e;
}
},
/* @__PURE__ */ m.createElement(
O,
{
className: this.getMenuClassName(),
"aria-orientation": this.props.vertical ? "vertical" : void 0,
items: this.items,
animate: this.animate,
isMenuVertical: this.props.vertical,
isDirectionRightToLeft: this.directionHolder.getIsDirectionRightToLeft(),
focusedItemId: this.state.focusedItemId,
lastItemIdToBeOpened: t,
tabbableItemId: this.state.tabbableItemId,
itemRender: this.props.itemRender,
linkRender: this.props.linkRender,
menuGuid: this.menuItemId,
onMouseLeave: this.onItemMouseLeave,
onMouseOver: this.onItemMouseOver,
onMouseDown: this.onItemMouseDown,
onFocus: this.onItemFocus,
onClick: this.onItemClick,
onBlur: this.onItemBlur,
onOriginalItemNeeded: this.getInputItem,
role: this.props.role
}
)
);
}
/**
* @hidden
*/
componentDidMount() {
this.setState({ isFirstRender: !1 });
}
/**
* @hidden
*/
componentDidUpdate(t) {
(!!t.vertical != !!this.props.vertical || this.directionHolder.hasDirectionChanged()) && this.reset(), this.mouseOverHandler.OpenOnClick = this.props.openOnClick;
}
/**
* @hidden
*/
componentWillUnmount() {
this.clearItemHoverAndLeaveRequestsIfApplicable();
}
setFocusedItemId(t) {
this.setState((e) => {
const s = t === r ? e.tabbableItemId : g(t);
return { hoveredItemId: t === r || l(e.hoveredItemId) && l(t) ? e.hoveredItemId : r, focusedItemId: t, tabbableItemId: s };
});
}
setHoveredItemId(t) {
this.setState((e) => l(t) && l(e.focusedItemId) ? {
hoveredItemId: t,
focusedItemId: e.focusedItemId,
tabbableItemId: e.tabbableItemId
} : { hoveredItemId: t, focusedItemId: r, tabbableItemId: c });
}
getMenuClassName() {
return f(
"k-reset",
"k-header",
"k-menu",
{ "k-menu-horizontal": !this.props.vertical },
{ "k-menu-vertical": this.props.vertical },
this.props.className
);
}
clearItemHoverAndLeaveRequestsIfApplicable() {
this.itemHoverRequest && (clearTimeout(this.itemHoverRequest), this.itemHoverRequest = null), this.itemLeaveRequest && (clearTimeout(this.itemLeaveRequest), this.itemLeaveRequest = null);
}
isItemWithDefaultClose(t) {
return !this.props.customCloseItemIds || this.props.customCloseItemIds.indexOf(t) === -1;
}
checkIsDirectionRightToLeft() {
return !!(this.props.dir !== void 0 ? this.props.dir === "rtl" : this.menuWrapperEl && getComputedStyle(this.menuWrapperEl).direction === "rtl");
}
prepareItems() {
const { items: t, inputItems: e } = R(this.props.items, this.props.children);
this.items = t, this.inputItems = e;
}
dispatchSelectEventIfWired(t, e) {
v(this.props.onSelect, t, this, { item: this.getInputItem(e), itemId: e });
}
};
n.propTypes = {
vertical: i.bool,
items: i.arrayOf(i.object),
style: i.object,
animate: i.oneOfType([
i.bool,
i.shape({
openDuration: i.number,
closeDuration: i.number
})
]),
dir: i.string,
hoverOpenDelay: i.number,
hoverCloseDelay: i.number,
openOnClick: i.bool,
itemRender: i.any,
linkRender: i.any,
customCloseItemIds: i.arrayOf(i.string),
onSelect: i.func,
role: i.string
}, n.defaultProps = { vertical: !1, animate: !0 };
let u = n;
export {
u as Menu
};