UNPKG

@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
/** * @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 };