UNPKG

@progress/kendo-react-treeview

Version:

React TreeView displays hierarchical data in a traditional tree structure, supports user interaction. KendoReact TreeView package

261 lines (260 loc) 9.82 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 l from "react"; import a from "prop-types"; import { treeIdUtils as u, validatePackage as f, TreeFieldsService as g, classNames as F, WatermarkOverlay as E, Keys as d, hasChildren as b, dispatchEvent as p, resolveItemId as C, kendoThemeMaps as v, isEnabledAndAllParentsEnabled as D } from "@progress/kendo-react-common"; import x from "./utils/getItemIdUponKeyboardNavigation.mjs"; import { getNodePosition as k } from "./utils/utils.mjs"; import { TreeViewItem as S } from "./TreeViewItem.mjs"; import { packageMetadata as y } from "./package-metadata.mjs"; import { EXPAND_FIELD as w, SELECT_FIELD as L, ICON_FIELD as _, HAS_CHILDREN_FIELD as H, CHILDREN_FIELD as I, TEXT_FIELD as P, DISABLED_FIELD as M, CHECK_FIELD as R, CHECK_INDETERMINATE_FIELD as T } from "./utils/consts.mjs"; const { sizeMap: N } = v, r = class r extends l.Component { constructor(t) { super(t), this.state = { focusedItemId: void 0, focusedItemPublicId: void 0, tabbableItemId: u.ZERO_LEVEL_ZERO_NODE_ID }, this.fieldsSvc = null, this.allowExplicitFocus = !1, this.showLicenseWatermark = !1, this._element = null, this.onFocusDomElNeeded = (e) => { this.allowExplicitFocus && this.focusDomItem(e); }, this.onCheckChange = (e, i, s) => { this.setFocus(s), this.dispatchCheckChange(e, i, s); }, this.onExpandChange = (e, i, s) => { this.setFocus(s), this.dispatchExpandChange(e, i, s); }, this.onPress = (e, i, s) => { this.props.onItemDragStart && this.props.onItemDragStart.call(void 0, { target: this, item: i, itemHierarchicalIndex: s }); }, this.onDrag = (e, i, s) => { const { pageX: o, pageY: n, clientX: h, clientY: c } = e; this.props.onItemDragOver && this.props.onItemDragOver.call(void 0, { target: this, item: i, itemHierarchicalIndex: s, pageX: o, pageY: n, clientX: h, clientY: c }); }, this.onRelease = (e, i, s) => { const { pageX: o, pageY: n, clientX: h, clientY: c } = e; this.props.onItemDragEnd && this.props.onItemDragEnd.call(void 0, { target: this, item: i, itemHierarchicalIndex: s, pageX: o, pageY: n, clientX: h, clientY: c }); }, this.onItemClick = (e, i, s) => { this.setFocus(s), this.dispatchItemClick(e, i, s); }, this.onFocus = () => { clearTimeout(this.blurRequest), this.state.focusedItemId === void 0 && this.data.length && this.setFocus(this.state.tabbableItemId); }, this.onBlur = () => { clearTimeout(this.blurRequest), this.blurRequest = window.setTimeout(() => this.setFocus(void 0), 0); }, this.onKeyDown = (e) => { const i = this.getFocusedItem(); if (i && this.fieldsSvc) { const s = x(i, this.state.focusedItemId, this.data, e.keyCode, this.fieldsSvc); s !== this.state.focusedItemId && (e.preventDefault(), this.allowExplicitFocus = !0, this.setFocus(s)), this.dispatchEventsOnKeyDown(e, i); } }, this.onContextMenu = (e, i, s) => { if (this.props.onContextMenu) { const o = { target: this, syntheticEvent: e, nativeEvent: e.nativeEvent, item: i, itemID: s }; this.props.onContextMenu.call(void 0, o); } }, this.showLicenseWatermark = !f(y, { component: "TreeView" }); } get treeGuid() { return this.props.id + "-accessibility-id"; } /** * @hidden */ get element() { return this._element; } /** * @hidden */ render() { this.fieldsSvc = new g(this.props); const { size: t, className: e } = this.props; return /* @__PURE__ */ l.createElement( "div", { id: this.props.id, style: { position: "relative", ...this.props.style }, className: F( "k-treeview", { [`k-treeview-${N[t] || t}`]: t, "k-user-select-none": this.props.draggable, "k-rtl": this.props.dir === "rtl" }, e ), onKeyDown: this.onKeyDown, onFocus: this.onFocus, onBlur: this.onBlur, role: "tree", "aria-multiselectable": this.ariaMultiSelectable ? !0 : void 0, "aria-label": this.props["aria-label"], "aria-labelledby": this.props["aria-labelledby"], ref: (i) => this._element = i, tabIndex: this.props.tabIndex }, /* @__PURE__ */ l.createElement("ul", { className: "k-treeview-lines k-treeview-group", role: "group" }, this.data.map((i, s) => /* @__PURE__ */ l.createElement( S, { id: this.props.id + "-item-" + s, item: i, position: k(s, this.data), itemId: s.toString(), treeGuid: this.treeGuid, animate: this.props.animate, focusedItemId: this.state.focusedItemId, tabbableItemId: this.state.tabbableItemId, fieldsService: this.fieldsSvc, itemUI: this.props.item, checkboxes: this.props.checkboxes, ariaMultiSelectable: this.ariaMultiSelectable, onItemClick: this.onItemClick, onFocusDomElNeeded: this.onFocusDomElNeeded, draggable: this.props.draggable, onPress: this.onPress, onDrag: this.onDrag, onRelease: this.onRelease, expandIcons: this.props.expandIcons, iconField: this.props.iconField, onExpandChange: this.onExpandChange, onCheckChange: this.onCheckChange, onContextMenu: this.onContextMenu, key: s, size: t, isRtl: this.props.dir === "rtl" } ))), this.showLicenseWatermark && /* @__PURE__ */ l.createElement(E, null) ); } /** * @hidden */ componentDidUpdate() { this.allowExplicitFocus = !1, this.refocusDueToFocusIdField(); } dispatchEventsOnKeyDown(t, e) { if (this.fieldsSvc === null) return; const i = () => this.fieldsSvc && D(this.state.focusedItemId, this.data, this.fieldsSvc); t.keyCode === d.left && this.fieldsSvc.expanded(e) && i() ? this.dispatchExpandChange(t, e, this.state.focusedItemId) : t.keyCode === d.right && !this.fieldsSvc.expanded(e) && (this.fieldsSvc.hasChildren(e) || b(e, this.props.childrenField)) && i() ? this.dispatchExpandChange(t, e, this.state.focusedItemId) : t.keyCode === d.enter && i() ? this.dispatchItemClick(t, e, this.state.focusedItemId) : t.keyCode === d.space && i() && (t.preventDefault(), this.dispatchCheckChange(t, e, this.state.focusedItemId)); } setFocus(t) { if (t && this.fieldsSvc) if (this.fieldsSvc.focusIdField) { const e = this.getItemById(t); this.setState({ focusedItemId: t, focusedItemPublicId: this.fieldsSvc.focusId(e) }); } else this.setState({ focusedItemId: t }); else this.setState((e) => ({ focusedItemId: void 0, focusedItemPublicId: void 0, tabbableItemId: e.focusedItemId })); } getFocusedItem() { return this.state.focusedItemId ? this.getItemById(this.state.focusedItemId) : void 0; } getItemById(t) { return u.getItemById(t, this.data, this.props.childrenField || I); } dispatchCheckChange(t, e, i) { p(this.props.onCheckChange, t, this, { item: e, itemHierarchicalIndex: i }); } dispatchExpandChange(t, e, i) { p(this.props.onExpandChange, t, this, { item: e, itemHierarchicalIndex: i }); } dispatchItemClick(t, e, i) { p(this.props.onItemClick, t, this, { item: e, itemHierarchicalIndex: i }); } refocusDueToFocusIdField() { if (this.fieldsSvc && this.fieldsSvc.focusIdField) { const t = this.state.focusedItemPublicId; if (t) { const e = this.props.getFocusHierarchicalIndex ? this.props.getFocusHierarchicalIndex(t) : C( t, this.fieldsSvc.focusIdField, this.data, this.props.childrenField ); e !== this.state.focusedItemId && (this.allowExplicitFocus = !0, this.setState({ focusedItemId: e })); } } } get ariaMultiSelectable() { return this.props["aria-multiselectable"] === !0 || this.props["aria-multiselectable"] === "true"; } get data() { return this.props.data || []; } focusDomItem(t) { t.focus(); } /** * Returns the `guid` which is associated with the TreeView. */ get guid() { return this.treeGuid; } }; r.propTypes = { data: a.arrayOf(a.any), animate: a.bool, tabIndex: a.number, focusIdField: a.string, getHierarchicalIndexById: a.func, onExpandChange: a.func, onItemClick: a.func, expandField: a.string, selectField: a.string, iconField: a.string, childrenField: a.string, hasChildrenField: a.string, textField: a.string, disableField: a.string, item: a.any, "aria-multiselectable": (t, e, i) => t[e] !== void 0 && t[e] !== !0 && t[e] !== !1 && t[e] !== "true" && t[e] !== "false" ? new Error( "Invalid prop `" + e + "` supplied to `" + i + "`. Validation failed." ) : null, "aria-label": a.string, "aria-labelledby": a.string, size: a.oneOf([null, "small", "medium", "large"]), dir: a.string }, r.defaultProps = { animate: !0, expandField: w, selectField: L, iconField: _, hasChildrenField: H, childrenField: I, textField: P, disableField: M, checkField: R, checkIndeterminateField: T, size: "medium" }; let m = r; export { m as TreeView };