@neo4j-ndl/react
Version:
React implementation of Neo4j Design System
181 lines • 8.46 kB
JavaScript
;
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TreeItemWrapper = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
/**
*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const classnames_1 = __importDefault(require("classnames"));
const react_1 = require("react");
const utils_1 = require("../_common/utils");
const icons_1 = require("../icons");
const tree_view_keyboard_helpers_1 = require("./tree-view-keyboard-helpers");
const TreeViewTrail_1 = require("./TreeViewTrail");
/**
* Handles keydown events for when the item itself is focused (wrapperRef.current)
* Moves the focus between the item and its children as well as toggles collapsing of the item
* @param event
* @param shouldDisableInteraction
* @param wrapperRef
* @param onCollapse
* @param item
* @returns
*/
const onWrapperKeyDown = (event, shouldDisableInteraction, wrapperRef, onCollapse, item) => {
if (shouldDisableInteraction || wrapperRef.current === null) {
return;
}
if (event.key === 'Enter' && onCollapse) {
onCollapse();
}
else if (event.key === 'ArrowRight') {
event.preventDefault();
if (item.canHaveSubItems && item.isCollapsed && onCollapse) {
onCollapse();
}
else {
const focusable = (0, utils_1.findFocusableChildren)(wrapperRef.current);
const [firstElement] = focusable;
if (firstElement instanceof HTMLElement) {
firstElement.focus();
}
}
event.preventDefault();
}
else if (event.key === 'ArrowLeft') {
event.preventDefault();
if (item.canHaveSubItems && !item.isCollapsed && onCollapse) {
onCollapse();
}
else {
(0, tree_view_keyboard_helpers_1.focusPreviousRow)(wrapperRef.current);
}
}
else if (event.key === 'ArrowDown') {
event.preventDefault();
(0, tree_view_keyboard_helpers_1.focusNextRow)(wrapperRef.current);
}
else if (event.key === 'ArrowUp') {
event.preventDefault();
(0, tree_view_keyboard_helpers_1.focusPreviousRow)(wrapperRef.current);
}
};
/**
* Handles keydown events for when one of the items children is focused
* Moves the focus between the children of the item and up to the parent if needed.
* Stops the event from propagating to the parent since it has it own keydown handler
* The parent is the wrapperRef.current and uses onWrapperKeyDown
* @param event
* @param shouldDisableInteraction
* @param wrapperRef
*/
const onInnerDivKeyDown = (event, shouldDisableInteraction, wrapperRef) => {
var _a;
if (shouldDisableInteraction) {
return;
}
event.stopPropagation();
if (event.key === 'ArrowRight') {
event.preventDefault();
const nextElement = (0, utils_1.findFocusableSibling)(wrapperRef, 'next');
if (nextElement) {
nextElement.focus();
}
}
else if (event.key === 'ArrowLeft') {
event.preventDefault();
const previousElement = (0, utils_1.findFocusableSibling)(wrapperRef, 'prev');
if (previousElement) {
previousElement.focus();
}
else {
(_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}
}
else if (event.key === 'ArrowDown' && wrapperRef.current !== null) {
event.preventDefault();
(0, tree_view_keyboard_helpers_1.focusCellInNextRow)(wrapperRef.current);
}
else if (event.key === 'ArrowUp' && wrapperRef.current !== null) {
event.preventDefault();
(0, tree_view_keyboard_helpers_1.focusCellInPreviousRow)(wrapperRef.current);
}
else if (event.shiftKey && event.key === 'Tab') {
const previousElement = (0, utils_1.findFocusableSibling)(wrapperRef, 'prev');
if (previousElement) {
event.preventDefault();
previousElement.focus();
}
}
else if (event.key === 'Tab') {
if (event.shiftKey) {
return;
}
const nextElement = (0, utils_1.findFocusableSibling)(wrapperRef, 'next');
if (nextElement) {
nextElement.focus();
event.preventDefault();
}
}
};
/**
* Used as a helper function to wrap the TreeItem component
* This adds the drag handle and trail to the start of a tree item.
* Useful if you want to add additional functionality to the tree item but still keep the drag handle and trail
* Is also used internally to create the TreeViewTextItem component
*/
function TreeItemWrapperInner(_a) {
var { depth, shouldDisableInteraction, shouldDisableSorting, isGhost, isIndicator, onCollapse, item, setNodeRef, setActivatorNodeRef, dragHandleProps, style, className, trails, children, indentationWidth, tabIndex, onFocus, ref } = _a,
// Need to destruct to avoid passing it to the component
// oxlint-disable-next-line no-unused-vars
restProps = __rest(_a, ["depth", "shouldDisableInteraction", "shouldDisableSorting", "isGhost", "isIndicator", "onCollapse", "item", "setNodeRef", "setActivatorNodeRef", "dragHandleProps", "style", "className", "trails", "children", "indentationWidth", "tabIndex", "onFocus", "ref"]);
const wrapperRef = (0, react_1.useRef)(null);
return ((0, jsx_runtime_1.jsx)("li", { ref: (el) => {
wrapperRef.current = el;
if (el === null) {
return;
}
setNodeRef(el);
}, className: (0, classnames_1.default)({
className,
'ndl-tree-view-list-item': true,
indicator: isIndicator,
'ndl-tree-view-list-item-placeholder': isGhost,
'ndl-tree-view-list-item-disable-interaction': shouldDisableInteraction,
}), style: Object.assign(Object.assign({}, style), { paddingLeft: isIndicator ? `${depth * indentationWidth}px` : 0 }), role: "treeitem", onFocus: onFocus, "aria-selected": item.isSelected && !item.isSkeletonLoading, "aria-expanded": item.canHaveSubItems ? !item.isCollapsed : undefined, onKeyDown: (event) => onWrapperKeyDown(event, shouldDisableInteraction !== null && shouldDisableInteraction !== void 0 ? shouldDisableInteraction : false, wrapperRef, onCollapse, item), children: (0, jsx_runtime_1.jsxs)("div", { role: "presentation", className: "ndl-tree-view-list-item-content", ref: ref, onKeyDown: (event) => onInnerDivKeyDown(event, shouldDisableInteraction !== null && shouldDisableInteraction !== void 0 ? shouldDisableInteraction : false, wrapperRef), children: [!shouldDisableSorting && ((0, jsx_runtime_1.jsx)("button", Object.assign({ className: "ndl-tree-view-drag-handle", ref: setActivatorNodeRef, "aria-label": "Pick up" }, dragHandleProps, { tabIndex: tabIndex, children: (0, jsx_runtime_1.jsx)(icons_1.DragIcon, {}) }))), trails.map((trail, index) => {
return (0, jsx_runtime_1.jsx)(TreeViewTrail_1.Trail, { variant: trail }, index);
}), children] }) }));
}
exports.TreeItemWrapper = TreeItemWrapperInner;
//# sourceMappingURL=TreeItemWrapper.js.map