@hitachivantara/uikit-react-core
Version:
Core React components for the NEXT Design System.
421 lines (420 loc) • 13.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const jsxRuntime = require("react/jsx-runtime");
const React = require("react");
const uikitReactUtils = require("@hitachivantara/uikit-react-utils");
const useForkRef = require("../../hooks/useForkRef.cjs");
const icons = require("../../icons.cjs");
const DescendantProvider = require("../../TreeView/internals/DescendantProvider.cjs");
const setId = require("../../utils/setId.cjs");
const VerticalNavigationContext = require("../VerticalNavigationContext.cjs");
const TreeViewContext = require("./TreeViewContext.cjs");
const TreeViewItem_styles = require("./TreeViewItem.styles.cjs");
const Tooltip = require("../../Tooltip/Tooltip.cjs");
const Typography = require("../../Typography/Typography.cjs");
const Avatar = require("../../Avatar/Avatar.cjs");
const OverflowTooltip = require("../../OverflowTooltip/OverflowTooltip.cjs");
const preventSelection = (event, disabled) => {
if (event.shiftKey || event.ctrlKey || event.metaKey || disabled) {
event.preventDefault();
}
};
const HvVerticalNavigationTreeViewItem = React.forwardRef(
function HvVerticalNavigationTreeViewItem2(props, ref) {
const {
id: idProp,
className,
classes: classesProp,
disabled: disabledProp = false,
selectable: selectableProp,
nodeId,
icon = null,
label,
href,
target,
payload,
onClick,
onMouseDown,
onFocus,
children,
disableTooltip,
...others
} = uikitReactUtils.useDefaultProps("HvVerticalNavigationTreeViewItem", props);
const { classes, cx } = TreeViewItem_styles.useClasses(classesProp);
const treeViewControlContext = React.useContext(TreeViewContext.TreeViewControlContext);
const { isExpanded, isSelected, isFocused, isDisabled, isChildSelected } = React.useContext(TreeViewContext.TreeViewStateContext);
const {
treeId,
mode,
collapsible,
toggleExpansion,
multiSelect,
selectNode,
selectRange,
disabledItemsFocusable,
registerNode,
unregisterNode,
mapFirstChar,
unMapFirstChar,
focus
} = treeViewControlContext;
const treeviewMode = mode === "treeview";
let id = null;
if (idProp != null) {
id = idProp;
} else if (treeId && nodeId) {
id = `${treeId}-${nodeId}`;
}
const [treeitemElement, setTreeitemElement] = React.useState();
const contentRef = React.useRef(null);
const handleRef = useForkRef.useForkRef(setTreeitemElement, ref);
const descendant = React.useMemo(
() => ({
element: treeitemElement,
id: nodeId
}),
[nodeId, treeitemElement]
);
const { isOpen, useIcons, hasAnyChildWithData } = React.useContext(
VerticalNavigationContext.VerticalNavigationContext
);
const { index, parentId, level } = DescendantProvider.useDescendant(descendant);
const expandable = collapsible && Array.isArray(children);
const expanded = isExpanded ? isExpanded(nodeId) : false;
const focused = isFocused ? isFocused(nodeId) : false;
const selected = isSelected ? isSelected(nodeId) : false;
const disabled = isDisabled ? isDisabled(nodeId) : false;
const selectable = selectableProp != null ? selectableProp : !collapsible || !expandable || !isOpen;
React.useEffect(() => {
if (registerNode && unregisterNode && index !== -1) {
registerNode({
id: nodeId,
idAttribute: id,
index,
parentId,
selectable,
expandable,
disabled: disabledProp,
onFocus,
payload
});
return () => {
unregisterNode(nodeId);
};
}
return void 0;
}, [
registerNode,
unregisterNode,
parentId,
index,
nodeId,
expandable,
disabledProp,
id,
selectable,
onFocus,
payload
]);
React.useEffect(() => {
if (mapFirstChar && unMapFirstChar && label && contentRef.current?.textContent) {
mapFirstChar(
nodeId,
contentRef.current?.textContent.substring(0, 1).toLowerCase()
);
return () => {
unMapFirstChar(nodeId);
};
}
return void 0;
}, [mapFirstChar, unMapFirstChar, nodeId, label]);
let ariaSelected;
if (multiSelect) {
ariaSelected = selected;
} else if (selected) {
ariaSelected = true;
}
const handleFocus = React.useCallback(
(event) => {
if (event.target === event.currentTarget) {
(event.target.ownerDocument || document).getElementById(treeId).focus({ preventScroll: true });
}
const unfocusable = !disabledItemsFocusable && disabled;
if (!focused && event.currentTarget === event.target && !unfocusable && focus) {
focus(event, nodeId);
}
},
[disabled, disabledItemsFocusable, focus, focused, nodeId, treeId]
);
const handleExpansion = React.useCallback(
(event) => {
if (!disabled) {
if (treeviewMode && !focused && focus) {
focus(event, nodeId);
}
const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey);
if (expandable && isOpen && !(multiple && isExpanded && isExpanded(nodeId))) {
if (toggleExpansion) toggleExpansion(event, nodeId);
}
}
},
[
disabled,
expandable,
focus,
focused,
isExpanded,
multiSelect,
nodeId,
toggleExpansion,
treeviewMode,
isOpen
]
);
const handleSelection = React.useCallback(
(event) => {
if (selectable && !disabled) {
if (treeviewMode && !focused && focus) {
focus(event, nodeId);
}
const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey);
if (multiple) {
if (event.shiftKey) {
if (selectRange) return selectRange(event, { end: nodeId });
} else if (selectNode) return selectNode(event, nodeId, true);
} else if (selectNode) return selectNode(event, nodeId);
} else {
return false;
}
},
[
disabled,
focus,
focused,
multiSelect,
nodeId,
selectNode,
selectRange,
selectable,
treeviewMode
]
);
const handleMouseDown = React.useCallback(
(event) => {
preventSelection(event, disabled);
if (onMouseDown) {
onMouseDown(event);
}
},
[disabled, onMouseDown]
);
const handleClick = React.useCallback(
(event) => {
if (!disabled) {
if (expandable && isOpen) {
handleExpansion(event);
}
if (selectable) {
handleSelection(event);
}
}
if (onClick) {
onClick(event);
}
},
[
disabled,
expandable,
handleExpansion,
handleSelection,
onClick,
selectable,
isOpen
]
);
const handleKeyDown = React.useCallback(
(event) => {
let isEventHandled = false;
const { key } = event;
if (event.altKey || event.ctrlKey || event.metaKey || event.currentTarget !== event.target) {
return;
}
if (contentRef.current === event.currentTarget) {
if (key === "Enter" || key === " ") {
if (expandable && isOpen) {
isEventHandled = handleExpansion(event);
}
if (selectable) {
isEventHandled = handleSelection(event);
}
}
if (isEventHandled) {
event.preventDefault();
event.stopPropagation();
}
}
},
[expandable, handleExpansion, handleSelection, selectable, isOpen]
);
const renderedContent = React.useMemo(() => {
const buttonLinkProps = {
href,
target
};
const hasChildren = !!children;
const showTooltip = !hasChildren && !isOpen && !disableTooltip;
const isLink = href !== void 0 && !disabled;
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip.HvTooltip, { placement: "right", title: showTooltip && label, children: /* @__PURE__ */ jsxRuntime.jsxs(
Typography.HvTypography,
{
id: setId.setId(id, "button"),
component: isLink ? "a" : "div",
...isLink ? buttonLinkProps : null,
ref: contentRef,
classes: {
root: cx(classes.content, {
[classes.link]: isLink,
[classes.minimized]: !isOpen
})
},
variant: "body",
disabled,
onClick: handleClick,
onMouseDown: handleMouseDown,
style: {
paddingLeft: (useIcons || !isOpen ? 0 : 10) + level * (collapsible ? 16 : 10)
},
role: isLink ? void 0 : "button",
...treeviewMode ? {
tabIndex: -1,
onFocus: handleFocus
} : {
tabIndex: selectable || expandable ? 0 : -1,
onKeyDown: handleKeyDown,
"aria-current": selectable && selected || !isOpen && isChildSelected?.(nodeId) ? href ? "page" : true : void 0,
"aria-expanded": expandable ? expanded : void 0,
"aria-controls": isOpen && expandable ? setId.setId(id, "group") : void 0,
"aria-label": payload?.label
},
children: [
/* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
className: classes.icon,
style: uikitReactUtils.mergeStyles(void 0, {
"--icon-margin-left": hasAnyChildWithData ? "auto" : "unset"
}),
children: [
!icon && useIcons ? /* @__PURE__ */ jsxRuntime.jsx(
Avatar.HvAvatar,
{
variant: "square",
size: "xs",
backgroundColor: "textSubtle",
children: payload?.label?.substring(0, 1)
}
) : useIcons && icon,
hasChildren && !isOpen ? /* @__PURE__ */ jsxRuntime.jsx(icons.HvIcon, { name: "Forwards", size: "xs", compact: true }) : hasAnyChildWithData && !isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", {})
]
}
),
isOpen && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: cx(classes.label, {
[classes.labelIcon]: useIcons,
[classes.labelExpandable]: !!expandable
}),
children: /* @__PURE__ */ jsxRuntime.jsx(OverflowTooltip.HvOverflowTooltip, { data: label })
}
),
isOpen && expandable && /* @__PURE__ */ jsxRuntime.jsx(icons.HvIcon, { name: "CaretDown", size: "xs", rotate: expanded })
]
}
) });
}, [
href,
target,
children,
isOpen,
disableTooltip,
disabled,
label,
id,
cx,
classes.content,
classes.link,
classes.minimized,
classes.icon,
classes.label,
classes.labelIcon,
classes.labelExpandable,
handleClick,
handleMouseDown,
useIcons,
level,
collapsible,
treeviewMode,
handleFocus,
selectable,
expandable,
handleKeyDown,
selected,
isChildSelected,
nodeId,
expanded,
payload?.label,
icon,
hasAnyChildWithData
]);
const renderedChildren = React.useMemo(
() => children && /* @__PURE__ */ jsxRuntime.jsx(
"ul",
{
id: setId.setId(id, "group"),
className: classes.group,
role: treeviewMode ? "group" : void 0,
children
}
),
[children, classes?.group, id, treeviewMode]
);
return /* @__PURE__ */ jsxRuntime.jsxs(
"li",
{
ref: handleRef,
id: id ?? void 0,
className: cx(
classes.node,
{
[classes.disabled]: disabled,
[classes.expandable]: expandable,
[classes.collapsed]: expandable && !expanded,
[classes.expanded]: expandable && expanded,
[classes.selectable]: selectable && !disabled,
[classes.unselectable]: !disabled && !selectable,
[classes.selected]: !disabled && selectable && selected || !isOpen && useIcons && isChildSelected && isChildSelected(nodeId),
[classes.unselected]: !disabled && selectable && !selected,
[classes.focused]: focused,
[classes.hide]: !isOpen && !useIcons
},
className
),
"data-hasicon": icon != null ? true : void 0,
...mode === "treeview" && {
role: "treeitem",
"aria-selected": ariaSelected,
"aria-expanded": expandable ? expanded : void 0,
"aria-disabled": disabled ? true : void 0
},
...others,
children: [
renderedContent,
isOpen && /* @__PURE__ */ jsxRuntime.jsx(DescendantProvider.DescendantProvider, { id: nodeId, level: level + 1, children: renderedChildren })
]
}
);
}
);
exports.treeViewItemClasses = TreeViewItem_styles.staticClasses;
exports.HvVerticalNavigationTreeViewItem = HvVerticalNavigationTreeViewItem;