@progress/kendo-react-layout
Version:
React Layout components enable you to create a perceptive and intuitive layout of web projects. KendoReact Layout package
241 lines (240 loc) • 7.76 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 a from "react";
import y from "prop-types";
import { PanelBarItem as L } from "./PanelBarItem.mjs";
import { getInitialState as Q, getFirstId as X, flatChildren as Y, isArrayEqual as Z, flatVisibleChildren as _, getFocusedChild as ee, renderChildren as te } from "./util.mjs";
import { useWebMcpRegister as re, Keys as m, classNames as ne } from "@progress/kendo-react-common";
import { NavigationAction as n } from "./interfaces/NavigationAction.mjs";
const U = (c) => {
const {
animation: u = !0,
children: o,
dir: N,
selected: w,
expanded: O,
expandMode: I = "multiple",
className: A,
keepItemsMounted: R = !1,
onSelect: C,
style: D,
isControlled: W
} = c, v = a.useRef(null), $ = a.useRef(null), T = a.useRef(void 0), x = a.useRef(null);
re("panelbar", $, c, c.webMcp);
const [p, f] = a.useState(() => {
const i = Q(c, I || "multiple");
return i.focused || (i.focused = X(c)), i;
}), E = I || "multiple", F = w !== void 0 ? w : p.selected, h = W ? O || [] : p.expanded, M = a.useCallback((t) => {
x.current = window.setTimeout(() => t());
}, []), g = a.useCallback(
(t) => {
const i = K, s = Y(a.Children.toArray(i));
let r, l;
switch (s.forEach((e) => {
e.props.uniquePrivateKey === (t.uniquePrivateKey || p.focused) && (r = e);
}), E) {
case "single":
l = [...r.props.parentUniquePrivateKey, r.props.uniquePrivateKey], Z(h, l) && (r.props.parentUniquePrivateKey ? l = [...r.props.parentUniquePrivateKey] : l = []);
break;
case "multiple": {
l = h.slice();
const e = l.indexOf(r.props.uniquePrivateKey);
e === -1 ? l.push(r.props.uniquePrivateKey) : l.splice(e, 1);
break;
}
default:
l = h.slice();
break;
}
f((e) => ({ ...e, selected: r.props.uniquePrivateKey, expanded: l })), C && C({
target: r,
expandedItems: l
});
},
[o, p.focused, E, h, C]
), d = a.useCallback(
(t, i = 0, s) => {
const r = K, l = _(a.Children.toArray(r)), e = ee(l, i, t, p.focused, s);
if (e) {
const k = h.slice();
if (s === n.Right && e && e.props && e.props.children && e.props.children.length > 0) {
if (k.push(e.props.uniquePrivateKey), f((b) => ({ ...b, expanded: [...new Set(k)] })), e.props.expanded) {
const b = e.props.children[0];
f((P) => ({ ...P, focused: b.props.uniquePrivateKey }));
}
} else if (s === n.Left && (e && e.props && e.props.parentUniquePrivateKey && e.props.parentUniquePrivateKey.length > 0 || e && e.props && !e.props.disabled && e.props.children && e.props.children.length > 0)) {
const b = e.props.parentUniquePrivateKey;
if (e.props.expanded) {
const P = e.props.uniquePrivateKey, q = k.indexOf(P);
k.splice(q, 1), f((J) => ({ ...J, expanded: k }));
} else if (e.props.level > 0) {
const P = e.props.parentUniquePrivateKey[b.length - 1];
f((q) => ({ ...q, focused: P }));
}
} else
f((b) => ({ ...b, focused: e.props.uniquePrivateKey }));
}
},
[o, p.focused, h]
), B = a.useCallback(
(t) => {
g(t), d(t);
},
[g, d]
), K = a.useMemo(() => te({
animation: u,
keepItemsMounted: R,
state: { ...p, selected: F },
expanded: h,
handleSelect: B,
children: o,
activeDescendantRef: T
}), [u, R, p, F, h, o, B]), S = a.useCallback(
(t, i) => {
let s;
switch (i) {
case n.First:
d(t, s, n.First);
break;
case n.Last:
d(t, s, n.Last);
break;
case n.Left:
d(t, s, n.Left);
break;
case n.Right:
d(t, s, n.Right);
break;
case n.Previous:
s = -1, d(t, s);
break;
case n.Next:
s = 1, d(t, s);
break;
case n.Toggle:
g(t);
break;
}
},
[d, g]
), H = a.useCallback(() => {
clearTimeout(x.current), p.wrapperFocused || f((t) => ({ ...t, wrapperFocused: !0 }));
}, [p.wrapperFocused]), V = a.useCallback(() => {
M(() => {
f((t) => ({ ...t, wrapperFocused: !1 }));
});
}, [M]), j = a.useCallback(
(t) => {
const i = v.current && getComputedStyle(v.current).direction === "rtl" || !1;
if (t.target === t.currentTarget) {
const s = t.keyCode;
let r;
switch (s) {
case m.left:
r = i ? n.Right : n.Left;
break;
case m.up:
r = n.Previous;
break;
case m.right:
r = i ? n.Left : n.Right;
break;
case m.down:
r = n.Next;
break;
case m.home:
r = n.First;
break;
case m.end:
r = n.Last;
break;
case m.space:
case m.enter:
r = n.Toggle;
break;
default:
r = null;
break;
}
r !== null && (t.preventDefault(), S(t, r));
}
},
[S]
);
a.useEffect(() => () => {
x.current && clearTimeout(x.current);
}, []);
const z = {
"aria-activedescendant": T.current
}, G = ne("k-panelbar", A);
return /* @__PURE__ */ a.createElement(
"ul",
{
ref: v,
dir: N,
role: "tree",
tabIndex: 0,
onKeyDown: j,
onFocus: H,
onBlur: V,
className: G,
style: D,
...z
},
K
);
};
U.propTypes = {
/**
* A collection of `PanelBarItem` components.
*/
children: y.oneOfType([
y.arrayOf(function(c, u) {
return c[u].type !== L ? new Error("PanelBar children should be either PanelBarItem or an array of PanelBarItem.") : null;
}),
function(c, u) {
const o = c[u];
return o && o.type !== L ? new Error("PanelBar children should be either PanelBarItem or an array of PanelBarItem.") : null;
}
]),
/**
* Expands the item or items that match the `selected` property while respecting the `expandMode` property (see [example]({% slug expandModes_panelbar %}#toc-single-expandMode)).
* To expand the item on the initial load of the PanelBar, define the `expanded` property of each PanelBarItem.
*/
selected: y.string,
/**
* Sets the expand mode of the PanelBar through the `single`, `multiple`, or `default` keywords (see [example]({% slug expandModes_panelbar %})).
*/
expandMode(c, u) {
const o = c[u];
return o !== "single" && o !== "multiple" && o !== "default" ? new Error(
`Invalid value '${o}' given to '${u}'. It must be either 'single', 'multiple' or 'default'.`
) : null;
},
/**
* Enables or disables the animation of the PanelBar items.
*/
animation: y.bool,
/**
* When enabled, keeps PanelBarItem content mounted in the DOM even when collapsed.
*/
keepItemsMounted: y.bool,
/**
* Fires when the expand mode of the PanelBar is set to `single` or `multiple`
* and an item is toggled (see [example]({% slug overview_panelbar %}#toc-expanded-state-management)).
*/
onSelect: y.func
};
U.defaultProps = {
expandMode: "multiple",
animation: !0,
keepItemsMounted: !1
};
export {
U as PanelBar
};