@progress/kendo-react-treeview
Version:
React TreeView displays hierarchical data in a traditional tree structure, supports user interaction. KendoReact TreeView package
212 lines (211 loc) • 8.68 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 t from "react";
import { classNames as n, Draggable as p, hasChildren as o, IconWrap as d, isItemExpandedAndWithChildren as l, treeIdUtils as m, withIdHOC as I, kendoThemeMaps as u } from "@progress/kendo-react-common";
import { caretAltDownIcon as f, caretAltLeftIcon as b, caretAltRightIcon as g } from "@progress/kendo-svg-icons";
import { Reveal as k } from "@progress/kendo-react-animation";
import { DOM_KENDO_ITEM_ID_FIELD as x, DOM_KENDO_TREEVIEW_GUID_FIELD as E } from "./utils/consts.mjs";
import { getNodePosition as C } from "./utils/utils.mjs";
const { sizeMap: v } = u, S = t.createContext(
(r) => r
), h = class h extends t.Component {
constructor() {
super(...arguments), this.onCheckChange = (e) => {
this.props.onCheckChange(e, this.item, this.itemId);
}, this.onExpandChange = (e) => {
this.props.onExpandChange(e, this.item, this.itemId);
}, this.onItemClick = (e) => {
this.props.onItemClick(e, this.item, this.itemId);
}, this.onPress = (e) => {
this.props.onPress(e.event, this.item, this.itemId);
}, this.onDrag = (e) => {
this.props.onDrag(e.event, this.item, this.itemId);
}, this.onRelease = (e) => {
this.props.onRelease(e.event, this.item, this.itemId);
}, this.onContextMenu = (e) => {
this.props.onContextMenu(e, this.item, this.itemId);
}, this.assignDraggableMeta = (e) => {
e && (e[x] = this.props.itemId, e[E] = this.props.treeGuid);
};
}
render() {
const e = this.renderSubitemsIfApplicable(), i = this.renderItemInPart();
return /* @__PURE__ */ t.createElement(
"li",
{
className: n("k-treeview-item"),
tabIndex: this.tabIndex,
role: "treeitem",
"aria-expanded": this.ariaExpanded,
"aria-selected": this.ariaSelected,
"aria-checked": this.ariaChecked,
"aria-disabled": this.disabled ? !0 : void 0,
ref: (s) => this.itemElement = s
},
/* @__PURE__ */ t.createElement("span", { className: `k-treeview-${this.props.position}`, ref: this.assignDraggableMeta }, this.renderExpandIcon(), this.renderCheckbox(), this.props.draggable ? /* @__PURE__ */ t.createElement(p, { onPress: this.onPress, onDrag: this.onDrag, onRelease: this.onRelease }, i) : i),
e && (this.props.animate ? /* @__PURE__ */ t.createElement(
k,
{
transitionEnterDuration: 200,
transitionExitDuration: 200,
style: { display: "block" },
children: e
}
) : e)
);
}
componentDidMount() {
const e = this.props.focusedItemId, i = this.itemId;
e && e === i && this.props.onFocusDomElNeeded(this.itemElement), this.checkboxElement && (this.checkboxElement.indeterminate = this.fieldsSvc.checkIndeterminate(this.item));
}
componentDidUpdate(e) {
const i = this.props.focusedItemId;
if (i && i !== e.focusedItemId && i === this.itemId && this.props.onFocusDomElNeeded(this.itemElement), this.checkboxElement) {
const s = this.fieldsSvc.checkIndeterminate(this.item);
this.checkboxElement.indeterminate !== s && (this.checkboxElement.indeterminate = s);
}
}
renderCheckbox() {
if (this.props.checkboxes) {
const e = this.props.size;
return /* @__PURE__ */ t.createElement("span", { className: n("k-checkbox-wrap") }, /* @__PURE__ */ t.createElement(
"input",
{
type: "checkbox",
className: n("k-checkbox k-rounded-md", {
[`k-checkbox-${v[e] || e}`]: e,
"k-disabled": this.disabled
}),
"aria-label": this.item.text,
checked: !!this.fieldsSvc.checked(this.item),
id: this.props.id,
tabIndex: -1,
onChange: this.onCheckChange,
ref: (i) => this.checkboxElement = i
}
));
}
}
renderExpandIcon() {
return this.props.expandIcons && // If it is explicitly said that the item has children (even not loaded yet)
// or if the item actually has children, then render the icon.
(this.fieldsSvc.hasChildren(this.item) || o(this.item, this.fieldsSvc.getChildrenField())) && // Allowing the toggle-button even with `disabled=true` might be a valid case!
// Re-evaluate the classes bellow if such scenario occurs
/* @__PURE__ */ t.createElement(
"span",
{
className: n("k-treeview-toggle", { "k-disabled": this.disabled }),
onClick: this.onExpandChange
},
/* @__PURE__ */ t.createElement(d, { ...this.getIconProps() })
);
}
renderSubitemsIfApplicable() {
const e = this.fieldsSvc.children(this.item);
return l(this.item, this.fieldsSvc) ? /* @__PURE__ */ t.createElement("ul", { className: "k-treeview-group", role: "group" }, e.map((i, s) => /* @__PURE__ */ t.createElement(
c,
{
item: i,
position: C(s, e),
itemId: m.createId(s, this.itemId),
treeGuid: this.props.treeGuid,
animate: this.props.animate,
focusedItemId: this.props.focusedItemId,
tabbableItemId: this.props.tabbableItemId,
fieldsService: this.props.fieldsService,
itemUI: this.props.itemUI,
checkboxes: this.props.checkboxes,
ariaMultiSelectable: this.props.ariaMultiSelectable,
onItemClick: this.props.onItemClick,
onFocusDomElNeeded: this.props.onFocusDomElNeeded,
draggable: this.props.draggable,
onPress: this.props.onPress,
onDrag: this.props.onDrag,
onRelease: this.props.onRelease,
expandIcons: this.props.expandIcons,
iconField: this.props.iconField,
onExpandChange: this.props.onExpandChange,
onCheckChange: this.props.onCheckChange,
onContextMenu: this.props.onContextMenu,
key: s,
size: this.props.size,
disabled: this.disabled,
isRtl: this.props.isRtl
}
))) : void 0;
}
renderItemInPart() {
const e = this.props.iconField, i = e && this.item[e];
return /* @__PURE__ */ t.createElement(
"span",
{
className: n("k-treeview-leaf", {
"k-focus": this.props.focusedItemId === this.itemId,
"k-selected": this.fieldsSvc.selected(this.item),
"k-disabled": this.disabled,
"k-touch-action-none": this.props.draggable
}),
onClick: this.onItemClick,
onContextMenu: this.onContextMenu
},
i && /* @__PURE__ */ t.createElement(d, { name: i.name, icon: i }),
/* @__PURE__ */ t.createElement("span", { className: "k-treeview-leaf-text" }, this.props.itemUI ? /* @__PURE__ */ t.createElement(this.props.itemUI, { item: this.item, itemHierarchicalIndex: this.itemId }) : this.fieldsSvc.text(this.item))
);
}
get fieldsSvc() {
return this.props.fieldsService;
}
get itemId() {
return this.props.itemId;
}
get item() {
return this.props.item;
}
get tabIndex() {
return (this.props.focusedItemId || this.props.tabbableItemId) === this.itemId ? 0 : -1;
}
get ariaExpanded() {
return this.fieldsSvc.hasChildren(this.item) || o(this.item, this.fieldsSvc.getChildrenField()) ? !!this.fieldsSvc.expanded(this.item) : void 0;
}
get disabled() {
return this.props.disabled || this.fieldsSvc.disabled(this.item);
}
get ariaChecked() {
if (this.props.checkboxes)
return this.fieldsSvc.checked(this.item) ? "true" : this.fieldsSvc.checkIndeterminate(this.item) ? "mixed" : "false";
}
get ariaSelected() {
if (this.fieldsSvc.selected(this.item))
return !0;
if (this.props.ariaMultiSelectable)
return this.disabled ? void 0 : !1;
}
getIconProps() {
const e = this.fieldsSvc.expanded(this.item);
return e && !o(this.item, this.fieldsSvc.getChildrenField()) ? { name: "loading" } : e ? { name: "caret-alt-down", icon: f } : {
name: this.props.isRtl ? "caret-alt-left" : "caret-alt-right",
icon: this.props.isRtl ? b : g
};
}
};
h.defaultProps = {
position: "top",
iconField: "svgIcon"
};
let a = h;
const c = I(
t.forwardRef((r, e) => {
const s = t.useContext(S).call(void 0, r);
return /* @__PURE__ */ t.createElement(a, { ref: e, ...s });
})
);
c.displayName = "TreeViewItem";
export {
c as TreeViewItem,
S as TreeViewItemPropsContext
};