Closed tujger closed 1 year ago
Indeed for TreeVIewContent
, I'll add it on the next release, thanks for the feedback!
For TreeViewContext
, could you give me a working example using it? For me it was not exported, and since I'm doing major breaking changes on it, knowing if it's public or private is important :+1:
We're overriding TreeItem with customization, so both components are necessary for. Then please provide the public version of it - I hope it's possible. There are fields we use:
const {
icons: contextIcons = {},
focus,
isExpanded,
isFocused,
isSelected,
isDisabled,
multiSelect,
disabledItemsFocusable,
mapFirstChar,
unMapFirstChar,
registerNode,
unregisterNode,
treeId,
} = React.useContext(TreeViewContext)
Thank you!
Could you provide a working reproduction, this Codesandbox template might be a good starting point.
Because as far as I know the context is not public in the lab.
It's not easy, the component is implemented along many other components within our package. It tries to represent foldable table rows based on TreeItem.
https://github.com/mui/mui-x/assets/12112326/20f528d6-3f3f-4e4b-94e7-669b660f180a
In that case, could you show me how you import the context ?
import TreeViewContext from '@mui/lab/TreeView/TreeViewContext';
(it was working...)
const ComponentTreeItem = React.forwardRef(function TreeItem(inProps, ref) {
const { branch, level, header, path, label: labelsGiven, labels } = inProps;
const props = useThemeProps({ props: inProps, name: 'MuiTreeItem' });
const {
children,
className,
collapseIcon,
ContentComponent = TreeItemContent,
ContentProps,
endIcon,
expandIcon,
disabled: disabledProp,
icon,
id: idProp,
label,
nodeId,
onClick,
onMouseDown,
TransitionComponent,
TransitionProps,
...other
} = props;
const {
icons: contextIcons = {},
focus,
isExpanded,
isFocused,
isSelected,
isDisabled,
multiSelect,
disabledItemsFocusable,
mapFirstChar,
unMapFirstChar,
registerNode,
unregisterNode,
treeId,
} = React.useContext(TreeViewContext);
let id = null;
if (idProp != null) {
id = idProp;
} else if (treeId && nodeId) {
id = `${treeId}-${nodeId}`;
}
const [treeitemElement, setTreeitemElement] = React.useState(null);
const contentRef = React.useRef(null);
const handleRef = useForkRef(setTreeitemElement, ref);
const descendant = React.useMemo(
() => ({
element: treeitemElement,
id: nodeId,
}),
[nodeId, treeitemElement],
);
const { index, parentId } = useDescendant(descendant);
const expandable = Boolean(Array.isArray(children) ? children.length : 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 ownerState = {
...props,
expanded,
focused,
selected,
disabled,
};
const classes = useUtilityClasses(ownerState);
let displayIcon;
let expansionIcon;
if (expandable) {
if (!expanded) {
expansionIcon = expandIcon || contextIcons.defaultExpandIcon;
} else {
expansionIcon = collapseIcon || contextIcons.defaultCollapseIcon;
}
}
if (expandable) {
displayIcon = contextIcons.defaultParentIcon;
} else {
displayIcon = endIcon || contextIcons.defaultEndIcon;
}
React.useEffect(() => {
// On the first render a node's index will be -1. We want to wait for the real index.
if (registerNode && unregisterNode && index !== -1) {
registerNode({
id: nodeId,
idAttribute: id,
index,
parentId,
expandable,
disabled: disabledProp,
});
return () => {
unregisterNode(nodeId);
};
}
return undefined;
}, [registerNode, unregisterNode, parentId, index, nodeId, expandable, disabledProp, id]);
React.useEffect(() => {
if (mapFirstChar && unMapFirstChar && label) {
mapFirstChar(nodeId, contentRef.current?.textContent.substring(0, 1).toLowerCase());
return () => {
unMapFirstChar(nodeId);
};
}
return undefined;
}, [mapFirstChar, unMapFirstChar, nodeId, label]);
let ariaSelected;
if (multiSelect) {
ariaSelected = selected;
} else if (selected) {
/* single-selection trees unset aria-selected on un-selected items.
*
* If the tree does not support multiple selection, aria-selected
* is set to true for the selected node and it is not present on any other node in the tree.
* Source: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
*/
ariaSelected = true;
}
function handleFocus(event) {
// DOM focus stays on the tree which manages focus with aria-activedescendant
if (event.target === event.currentTarget) {
ownerDocument(event.target).getElementById(treeId).focus({ preventScroll: true });
}
const unfocusable = !disabledItemsFocusable && disabled;
if (!focused && event.currentTarget === event.target && !unfocusable) {
focus(event, nodeId);
}
}
const row = React.useMemo(() => {//TODO: works for now
if (path.length > 1 && typeof path !== 'string') {
const level = path.length - 1;
const keyRow = [...Array(header.length).keys()].map((item, index) => index === level ? label : "")
return { ...keyRow }
} else if (typeof path === 'string') {
const keyRow = [...Array(header.length).keys()].map((item, index) => index === branch.length - 1 ? label : "")
return { ...keyRow }
} else {
const keyRow = [...Array(header.length).keys()].map((item, index) => index === 0 ? label : "")
return { ...keyRow }
}
}, [path.length, header])
const isLeaf = branch instanceof Array || false;
if (isLeaf) {
return <TableRow
className={selected ? "SELECTED_LEAF" : ""}
role="treeitem"
aria-expanded={expandable ? expanded : null}
aria-selected={ariaSelected}
aria-disabled={disabled || null}
ref={handleRef}
id={id}
tabIndex={-1}
{...other}
ownerState={ownerState}
onFocus={handleFocus}
{...props}
onClick={onClick}
row={labels}
>
{labelsGiven}
</TableRow>
}
return (<>
<TableRow
// className={clsx(classes.root, className)}
role="treeitem"
aria-expanded={expandable ? expanded : null}
aria-selected={ariaSelected}
aria-disabled={disabled || null}
ref={handleRef}
id={id}
tabIndex={-1}
{...other}
ownerState={ownerState}
onFocus={handleFocus}
>
<TreeTableItemContent
as={ContentComponent}
ref={contentRef}
classes={{
root: classes.content,
expanded: classes.expanded,
selected: classes.selected,
focused: classes.focused,
disabled: classes.disabled,
iconContainer: classes.iconContainer,
label: classes.label,
}}
label={label}
nodeId={nodeId}
onClick={onClick}
onMouseDown={onMouseDown}
icon={icon}
expansionIcon={expansionIcon}
displayIcon={displayIcon}
ownerState={ownerState}
{...ContentProps}
row={row}
/>
</TableRow>
{expanded && <DescendantProvider id={nodeId}>
{children}
</DescendantProvider>}
</>
);
});
import TreeViewContext from '@mui/lab/TreeView/TreeViewContext';
These imports are not public and can break with some bundlers. We only guarantee the imports of depth 0 and 1.
But you can do the same thing:
import { TreeViewContext } from "@mui/x-tree-view/TreeView/TreeViewContext";
See this example
I tried. But it fails on start now reporting the unresolved import. Despite it was not with '@mui/lab'.
Did you change for a named import like in my code example?
Ow, I missed {}. Yes, this way works, even for both components. Thank you! But as you said the internal API can be changed, so now TreeViewContext doesn't bring treeId
, and logic is broken :)
The treeId
should still be defined https://github.com/mui/mui-x/blob/51f831e31772b1eda05c62e8c4df292624669bac/packages/x-tree-view/src/TreeView/TreeView.tsx#L856
You're right! Actually, everything is fixed changing:
import TreeView from "@mui/lab/TreeView" -> import {TreeView} from "@mui/x-tree-view/TreeView";
import TreeItem from '@mui/lab/TreeItem' -> import {TreeItem} from '@mui/x-tree-view/TreeItem';
and so on. Thank you!
Sorry, it's me again..
But you can do the same thing:
import { TreeViewContext } from "@mui/x-tree-view/TreeView/TreeViewContext";
See this example
I set the following, and it was working for several weeks:
import {DescendantProvider, useDescendant} from "@mui/x-tree-view/TreeView/descendants";
import {TreeViewContext} from "@mui/x-tree-view/TreeView/TreeViewContext";
Suddenly, it's started reporting:
Returning to previous versions (even whole package.json) doesn't help.
Also, there is the error on the reference you've provided.
As mentioned by @flaviendelangle - you are trying to use an import deeper than 2nd level. At that point, you assume the responsibility and risk of using an API that we do not guarantee the stability of, especially during pre-release stages.
With the latest release, there have been a lot of changes to the TreeView
internals, and the mentioned export can be accessed via: @mui/x-tree-view/internals/TreeViewProvider/TreeViewContext
as of 6.0.0-alpha.4
.
Once again, please be aware that you are using undocumented API, and you assume the risk of adjusting to any breaking changes that happen to it.
Duplicates
Latest version
Summary 💡
TreeItemContent and TreeViewContext were available in alpha.142, and are not available in x-tree-view. Please return these exports. Thank you!
Examples 🌈
No response
Motivation 🔦
No response
Order ID 💳 (optional)
No response