diff --git a/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx b/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx index 74c3bb09e5..a14068f17d 100644 --- a/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx +++ b/app/packages/core/src/plugins/SchemaIO/components/DropdownView.tsx @@ -1,5 +1,5 @@ -import { MenuItem, Select } from "@mui/material"; -import React, { useState } from "react"; +import { IconButton, MenuItem, Select } from "@mui/material"; +import React, { useEffect, useMemo, useState } from "react"; import { useKey } from "../hooks"; import { getComponentProps, getFieldSx } from "../utils"; import autoFocus from "../utils/auto-focus"; @@ -8,6 +8,14 @@ import AlertView from "./AlertView"; import ChoiceMenuItemBody from "./ChoiceMenuItemBody"; import FieldWrapper from "./FieldWrapper"; +// if we want to support more icons in the future, add them here +const iconImports: { + [key: string]: () => Promise<{ default: React.ComponentType }>; +} = { + MoreVertIcon: () => import("@mui/icons-material/MoreVert"), + SettingsIcon: () => import("@mui/icons-material/Settings"), +}; + const MULTI_SELECT_TYPES = ["string", "array"]; export default function DropdownView(props: ViewPropsType) { @@ -24,7 +32,10 @@ export default function DropdownView(props: ViewPropsType) { description, color, variant, + icon, } = view; + const [IconComponent, setIconComponent] = + useState | null>(null); const [key, setUserChanged] = useKey(path, schema, data, true); const [selected, setSelected] = useState(false); @@ -52,24 +63,84 @@ export default function DropdownView(props: ViewPropsType) { ? rawDefaultValue.toString().split(separator) : rawDefaultValue; - const choiceLabels = choices.reduce((labels, choice) => { - labels[choice.value] = choice.label; - return labels; - }, {}); + const choiceLabels = useMemo(() => { + return choices.reduce((labels, choice) => { + labels[choice.value] = choice.label; + return labels; + }, {}); + }, [choices]); + + const getIconOnlyStyles = () => ({ + "&.MuiInputBase-root.MuiOutlinedInput-root.MuiInputBase-colorPrimary": { + backgroundColor: "transparent !important", + borderRadius: "0 !important", + border: "none !important", + boxShadow: "none !important", + "&:hover, &:focus": { + backgroundColor: "transparent !important", + boxShadow: "none !important", + }, + }, + "& .MuiSelect-select": { + padding: 0, + background: "transparent", + "&:focus": { + background: "transparent", + }, + }, + "& .MuiInputBase-root": { + background: "transparent", + }, + "& .MuiOutlinedInput-notchedOutline": { + border: "none", + }, + "& .MuiSelect-icon": { + display: "none", + }, + }); + + const getDefaultStyles = (selected: boolean) => ({ + ".MuiSelect-select": { + padding: "0.45rem 2rem 0.45rem 1rem", + opacity: selected ? 1 : 0.5, + }, + }); + + const getDropdownStyles = (icon: string | undefined, selected: boolean) => { + return icon ? getIconOnlyStyles() : getDefaultStyles(selected); + }; + + // Now, condense the code like this: const { MenuProps = {}, ...selectProps } = getComponentProps( props, "select", { sx: { - ".MuiSelect-select": { - padding: "0.45rem 2rem 0.45rem 1rem", - opacity: selected ? 1 : 0.5, - }, + ...getDropdownStyles(icon, selected), ...getFieldSx({ color, variant }), }, } ); + // dynamically import the icon component + useEffect(() => { + if (icon && iconImports[icon]) { + iconImports[icon]().then((module) => { + setIconComponent(() => module.default); + }); + } + }, [icon]); + + const renderIcon = () => { + if (!IconComponent) return null; + + return ( + + + + ); + }; + return (