@progress/kendo-react-layout
Version:
React Layout components enable you to create a perceptive and intuitive layout of web projects. KendoReact Layout package
256 lines (255 loc) • 8.68 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2026 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import * as r from "react";
import u from "prop-types";
import { dispatchEvent as oe, Keys as B, classNames as ce } from "@progress/kendo-react-common";
import { ZERO_LEVEL_ZERO_ITEM_ID as A, EMPTY_ID as i, getRootParentId as _, isIdEmptyOrZeroLevel as P, getItemById as S, isIdZeroLevel as O, getDirectParentId as W } from "../utils/itemsIdsUtils.mjs";
import { prepareInputItemsForInternalWork as se } from "../utils/prepareInputItemsForInternalWork.mjs";
import { getNewItemIdUponKeyboardNavigation as Z } from "../utils/getNewItemIdUponKeyboardNavigation.mjs";
import { getHoverOpenDelay as ue, getHoverCloseDelay as ie } from "../utils/hoverDelay.mjs";
import { MenuItemInternalsList as le } from "./MenuItemInternal.mjs";
import { DirectionHolder as ae } from "../utils/DirectionHolder.mjs";
import { MouseOverHandler as de } from "../utils/MouseOverHandler.mjs";
const q = {
focusedItemId: i,
hoveredItemId: i,
tabbableItemId: A
}, j = r.forwardRef((o, x) => {
const R = r.useRef(null), g = r.useRef(null), h = r.useRef(null), k = r.useRef(new ae()), D = r.useRef([]), F = r.useRef([]), l = r.useRef(o);
l.current = o;
const [f, L] = r.useState({ ...q }), C = r.useRef(f);
C.current = f;
const H = r.useRef(() => {
}), p = r.useRef(new de(o.openOnClick, () => H.current())), { items: z, inputItems: G } = se(
o.items,
o.children
);
D.current = z, F.current = G, k.current.setIsDirectionRightToLeft(U());
function U() {
return !!(l.current.dir !== void 0 ? l.current.dir === "rtl" : R.current && getComputedStyle(R.current).direction === "rtl");
}
const b = r.useCallback(() => {
g.current && (clearTimeout(g.current), g.current = null), h.current && (clearTimeout(h.current), h.current = null);
}, []), K = r.useCallback(() => {
b(), L({ ...q });
}, [b]);
H.current = K;
const y = r.useRef({
get element() {
return R.current;
},
reset: () => H.current()
});
r.useImperativeHandle(x, () => y.current, []);
const m = r.useCallback((e) => {
L((t) => {
const n = e === i ? t.tabbableItemId : _(e);
return { hoveredItemId: e === i || P(t.hoveredItemId) && P(e) ? t.hoveredItemId : i, focusedItemId: e, tabbableItemId: n };
});
}, []), a = r.useCallback((e) => {
L((t) => P(e) && P(t.focusedItemId) ? {
hoveredItemId: e,
focusedItemId: t.focusedItemId,
tabbableItemId: t.tabbableItemId
} : { hoveredItemId: e, focusedItemId: i, tabbableItemId: A });
}, []), I = r.useCallback((e) => S(e, F.current), []), T = r.useCallback(
(e, t) => {
oe(l.current.onSelect, e, y.current, {
item: I(t),
itemId: t
});
},
[I]
), E = r.useCallback((e) => !l.current.customCloseItemIds || l.current.customCloseItemIds.indexOf(e) === -1, []), N = r.useCallback(
(e) => {
var c, s;
const t = l.current, n = C.current;
if (t.openOnClick && n.hoveredItemId !== i) {
const d = e.target;
((c = R.current) == null ? void 0 : c.contains(d)) === !1 && (t.id && ((s = d.closest) != null && s.call(d, `[id^="${t.id}_"]`)) || a(i));
}
},
[a]
), Y = r.useCallback(
(e) => {
const t = C.current, n = l.current, c = D.current;
if (t.focusedItemId !== i) {
const s = S(t.focusedItemId, c);
let d = Z(
c,
s.id,
e.keyCode,
e.key,
n.vertical,
k.current.getIsDirectionRightToLeft()
);
const v = S(d, c);
if (v != null && v.separator && (d = Z(
c,
d,
e.keyCode,
e.key,
n.vertical,
k.current.getIsDirectionRightToLeft()
)), s.id !== d && (e.preventDefault(), m(d)), (e.keyCode === B.enter || e.keyCode === B.space) && !s.disabled && (p.current.handleItemSelectedViaKeyboard(), T(e, s.id), !e.isDefaultPrevented() && s.items.length === 0 && s.url && window.location.assign(s.url)), e.keyCode === B.esc && O(s.id) && n.onClose) {
const w = I(s.id);
n.onClose({
target: y.current,
item: w,
itemId: s.id
});
}
}
},
[m, T, I]
), $ = r.useCallback(
(e) => {
const t = C.current, n = l.current, c = n.openOnClick && !O(e) && t.hoveredItemId !== i;
(p.current.IsMouseOverEnabled || c) && (b(), g.current = window.setTimeout(() => {
a(e), g.current = null;
}, ue(n)));
},
[b, a]
), J = r.useCallback(
(e) => {
const t = C.current, n = l.current, c = n.openOnClick && !O(e) && t.hoveredItemId !== i;
(p.current.IsMouseOverEnabled || c) && E(e) && (b(), h.current = window.setTimeout(() => {
a(c ? W(e) : i), h.current = null;
}, ie(n)));
},
[b, E, a]
), Q = r.useCallback(
(e) => {
C.current.hoveredItemId === i ? m(e) : L((n) => ({
focusedItemId: e,
hoveredItemId: n.hoveredItemId,
tabbableItemId: _(e)
}));
},
[m]
), X = r.useCallback(
(e, t) => {
const n = D.current, c = S(t, n), s = C.current, d = l.current;
if (!c.disabled) {
const v = O(t), w = !c.items || c.items.length === 0;
v ? (m(t), w ? a(i) : d.openOnClick && s.hoveredItemId !== i && _(s.hoveredItemId) === t ? a(i) : a(t)) : w && (m(t), a(i)), T(e, t), !e.isDefaultPrevented() && c.url && window.location.assign(c.url);
}
},
[m, a, T]
), ee = r.useCallback(
(e, t) => {
const n = l.current;
n.onClose && n.onClose({
target: y.current,
item: I(e),
itemId: e,
popupCloseEvent: t
});
},
[I]
), te = r.useCallback(
(e, t) => {
var c;
const n = l.current;
if (E(e) && m(i), ((c = t.relatedTarget) == null ? void 0 : c.nodeName) === "LI") {
const s = t.relatedTarget.getAttribute("id");
if (s != null && s.includes(n.id))
return;
}
if (O(e) && n.onClose) {
const s = I(e);
n.onClose({
target: y.current,
item: s,
itemId: e
});
}
},
[E, m, I]
), V = r.useRef(o.vertical);
r.useEffect(() => () => {
b();
}, [b]), r.useEffect(() => (o.openOnClick && document.addEventListener("mousedown", N), () => {
document.removeEventListener("mousedown", N);
}), [o.openOnClick, N]), r.useEffect(() => {
const e = !!V.current != !!o.vertical, t = k.current.hasDirectionChanged();
(e || t) && K(), p.current.OpenOnClick = o.openOnClick, V.current = o.vertical;
});
const re = () => ce(
"k-reset",
"k-header",
"k-menu",
{ "k-menu-horizontal": !o.vertical },
{ "k-menu-vertical": o.vertical },
o.className
);
let M;
f.hoveredItemId ? M = f.hoveredItemId : f.focusedItemId ? M = W(f.focusedItemId) : M = i;
const ne = o.animate !== void 0 ? o.animate : !0;
return /* @__PURE__ */ r.createElement(
"div",
{
id: o.id,
onKeyDown: Y,
style: o.style,
className: k.current.getIsDirectionRightToLeft() ? "k-rtl" : void 0,
ref: R
},
/* @__PURE__ */ r.createElement(
le,
{
className: re(),
"aria-orientation": o.vertical ? "vertical" : void 0,
items: D.current,
animate: ne,
isMenuVertical: o.vertical,
isDirectionRightToLeft: k.current.getIsDirectionRightToLeft(),
focusedItemId: f.focusedItemId,
lastItemIdToBeOpened: M,
tabbableItemId: f.tabbableItemId,
itemRender: o.itemRender,
linkRender: o.linkRender,
menuGuid: o.id,
onMouseLeave: J,
onMouseOver: $,
onFocus: Q,
onClick: X,
onBlur: te,
onOriginalItemNeeded: I,
onPopupClose: ee,
role: o.role
}
)
);
});
j.propTypes = {
vertical: u.bool,
items: u.arrayOf(u.object),
style: u.object,
animate: u.oneOfType([
u.bool,
u.shape({
openDuration: u.number,
closeDuration: u.number
})
]),
dir: u.string,
hoverOpenDelay: u.number,
hoverCloseDelay: u.number,
openOnClick: u.bool,
itemRender: u.any,
linkRender: u.any,
customCloseItemIds: u.arrayOf(u.string),
onSelect: u.func,
onClose: u.func,
role: u.string
};
j.displayName = "Menu";
export {
j as Menu
};