UNPKG

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