Open i19s-frank opened 4 years ago
Hello Denis,
I have implemented a solution fit to our needs. Since I don't have the time to adapt it into a meaningful PR I wanted to at least share the idea the solution is based on.
Since Material doesn't provide a component like the antd field selector, I went with a List with sticky Headers.
The code is in TS but you get the idea:
interface FieldCascaderProps extends FieldProps {
selectedField: string | Empty,
parentField: string | Empty,
}
interface Section {
path: string,
label: string,
fields: FieldItem[],
}
const MaterialFieldCascader = (props: FieldCascaderProps) => {
const {
items, placeholder, selectedKey, setField
} = props;
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
width: '100%',
maxWidth: 360,
backgroundColor: theme.palette.background.paper,
position: 'relative',
overflow: 'auto',
maxHeight: 300,
},
listSection: {
backgroundColor: 'inherit',
},
ul: {
backgroundColor: 'inherit',
padding: 0,
},
nested: {
paddingLeft: theme.spacing(4),
},
fieldSelectButton: {}
}),
);
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
const handleClick = (event: React.MouseEvent<any>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const onFieldSeleced = (path: string) => {
setField(path);
}
const open = Boolean(anchorEl);
const id = open ? 'material-field-cascader-popover' : undefined;
const sections: Section[] = [];
let selectedTemp: string = placeholder!;
for (let i in items) {
let item = items[i];
if (!item.items) {
throw new Error("Cannot handle leaves in the root");
}
if (!item.path) {
throw new Error("Path is missing!");
}
let section = {
path: item.path, fields: [], label: item.label!
};
sections.push(section);
handleChildren(item.items, sections, section);
}
function handleChildren(children: FieldItems, sections: Section[], parent: Section) {
for (let i in children) {
let child = children[i];
// this is a leaf
if (!child.items) {
if (child.path === selectedKey) {
selectedTemp = parent.label + " / " + child.label;
}
parent.fields.push(child)
} else {
let section = {
path: child.path!, fields: [], label: parent.label + " / " + child.label
};
sections.push(section);
handleChildren(child.items, sections, section);
}
}
}
const selected = selectedTemp;
return <div>
<Button aria-describedby={id} variant="text" className={classes.fieldSelectButton}
onClick={handleClick}>
{selected}
</Button>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
>
<List className={classes.root} subheader={<li/>}>
{sections.map((section) => (
<li id={`section-${section.path}`} key={`section-${section.path}`}
className={classes.listSection}>
<ul className={classes.ul}>
<ListSubheader>{`${section.label}`}</ListSubheader>
{section.fields.map((field) => (
<ListItem id={`item-${field.path}`} key={`item-${field.path}`}
className={classes.nested} onClick={(e) => {
onFieldSeleced(field.path!);
handleClose();
}}>
<ListItemText primary={`${field.label}`}/>
</ListItem>
))}
</ul>
</li>
))}
</List>
</Popover>
</div>;
}
export default MaterialFieldCascader;
The implementation obviously isn't complete.
Any news on this?
I'll be working on features for MUI soon. It would be great if someone open PR with code above
Is your feature request related to a problem? Please describe. I have to migrate from antd to material but am strongly relying on the FieldCascader.
Describe the solution you'd like Implement a MaterialFieldCascader.
Describe alternatives you've considered I am currently investiganting whether I can implement it myself.