Menu.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Copyright 2021-2024 Avaiga Private Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  5. * the License. You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  10. * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  11. * specific language governing permissions and limitations under the License.
  12. */
  13. import React, { useCallback, useMemo, useState, MouseEvent, CSSProperties } from "react";
  14. import MenuIco from "@mui/icons-material/Menu";
  15. import ListItemButton from "@mui/material/ListItemButton";
  16. import Drawer from "@mui/material/Drawer";
  17. import List from "@mui/material/List";
  18. import Avatar from "@mui/material/Avatar";
  19. import CardHeader from "@mui/material/CardHeader";
  20. import ListItemAvatar from "@mui/material/ListItemAvatar";
  21. import Box from "@mui/material/Box";
  22. import Tooltip from "@mui/material/Tooltip";
  23. import { Theme, useTheme } from "@mui/system";
  24. import { SingleItem } from "./lovUtils";
  25. import { createSendActionNameAction } from "../../context/taipyReducers";
  26. import { MenuProps } from "../../utils/lov";
  27. import { useClassNames, useDispatch, useModule } from "../../utils/hooks";
  28. import { emptyArray } from "../../utils";
  29. import { getComponentClassName } from "./TaipyStyle";
  30. const boxDrawerStyle = { overflowX: "hidden" } as CSSProperties;
  31. const headerSx = { padding: 0 };
  32. const avatarSx = { bgcolor: (theme: Theme) => theme.palette.text.primary };
  33. const baseTitleProps = { noWrap: true, variant: "h6" } as const;
  34. const Menu = (props: MenuProps) => {
  35. const { label, onAction = "", lov, width, inactiveIds = emptyArray, active = true } = props;
  36. const [selectedValue, setSelectedValue] = useState<string>("");
  37. const [opened, setOpened] = useState(false);
  38. const dispatch = useDispatch();
  39. const theme = useTheme();
  40. const module = useModule();
  41. const className = useClassNames(props.libClassName, props.dynamicClassName, props.className);
  42. const clickHandler = useCallback(
  43. (evt: MouseEvent<HTMLElement>) => {
  44. if (active) {
  45. const { id: key = "" } = evt.currentTarget.dataset;
  46. setSelectedValue(() => {
  47. dispatch(createSendActionNameAction("menu", module, onAction, key));
  48. return key;
  49. });
  50. }
  51. },
  52. [active, dispatch, module, onAction]
  53. );
  54. const openHandler = useCallback((evt: MouseEvent<HTMLElement>) => {
  55. evt.stopPropagation();
  56. setOpened((o) => !o);
  57. }, []);
  58. const selected = useMemo(() => {
  59. const selected = Array.isArray(props.selected) ? props.selected : [];
  60. if (selectedValue && !selected.includes(selectedValue)) {
  61. return [...selected, selectedValue];
  62. }
  63. return selected;
  64. }, [props.selected, selectedValue]);
  65. const [drawerSx, titleProps] = useMemo(() => {
  66. const drawerWidth = opened ? width : `calc(${theme.spacing(9)} + 1px)`;
  67. const titleWidth = opened ? `calc(${width} - ${theme.spacing(10)})` : undefined;
  68. return [
  69. {
  70. width: drawerWidth,
  71. flexShrink: 0,
  72. "& .MuiDrawer-paper": {
  73. width: drawerWidth,
  74. boxSizing: "border-box",
  75. transition: "width 0.3s",
  76. },
  77. transition: "width 0.3s",
  78. },
  79. { ...baseTitleProps, width: titleWidth },
  80. ];
  81. }, [opened, width, theme]);
  82. return lov && lov.length ? (
  83. <Drawer
  84. variant="permanent"
  85. anchor="left"
  86. sx={drawerSx}
  87. className={`${className} ${getComponentClassName(props.children)}`}
  88. >
  89. <Box style={boxDrawerStyle}>
  90. <List>
  91. <ListItemButton key="taipy_menu_0" onClick={openHandler}>
  92. <ListItemAvatar>
  93. <CardHeader
  94. sx={headerSx}
  95. avatar={
  96. <Tooltip title={label || false}>
  97. <Avatar sx={avatarSx}>
  98. <MenuIco />
  99. </Avatar>
  100. </Tooltip>
  101. }
  102. title={label}
  103. titleTypographyProps={titleProps}
  104. />
  105. </ListItemAvatar>
  106. </ListItemButton>
  107. {lov.map((elt) => (
  108. <SingleItem
  109. key={elt.id}
  110. value={elt.id}
  111. item={elt.item}
  112. selectedValue={selected}
  113. clickHandler={clickHandler}
  114. disabled={!active || inactiveIds.includes(elt.id)}
  115. withAvatar={true}
  116. titleTypographyProps={titleProps}
  117. />
  118. ))}
  119. </List>
  120. </Box>
  121. {props.children}
  122. </Drawer>
  123. ) : null;
  124. };
  125. export default Menu;