Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

COM-303 Refactor theming of SplitButton #1602

Merged
109 changes: 84 additions & 25 deletions packages/admin/admin/src/common/buttons/split/SplitButton.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,95 @@
import { ChevronDown } from "@comet/admin-icons";
import { Button, ButtonGroup, ButtonGroupProps, MenuItem, MenuList, Popover, PopoverProps } from "@mui/material";
import { withStyles } from "@mui/styles";
import {
Button,
ButtonGroup as MuiButtonGroup,
ButtonGroupProps,
MenuItem as MuiMenuItem,
MenuList as MuiMenuList,
Popover as MuiPopover,
} from "@mui/material";
import { styled, useThemeProps } from "@mui/material/styles";
import { ThemedComponentBaseProps } from "helpers/ThemedComponentBaseProps";
import * as React from "react";
import { PropsWithChildren } from "react";

import { useStoredState } from "../../../hooks/useStoredState";
import { SplitButtonContext } from "./SplitButtonContext";

export interface SplitButtonProps extends ButtonGroupProps<any> {
export type SplitButtonClassKey = "root" | "activeButton" | "popover" | "menuList" | "menuItem";

export interface SplitButtonProps
extends ButtonGroupProps<any>,
ThemedComponentBaseProps<{
root: typeof MuiButtonGroup;
activeButton: typeof Button;
popover: typeof MuiPopover;
menuList: typeof MuiMenuList;
menuItem: typeof MuiMenuItem;
}> {
selectIcon?: React.ReactNode;
selectedIndex?: number;
onSelectIndex?: (index: number, item: React.ReactElement) => void;
showSelectButton?: boolean;
localStorageKey?: string;
autoClickOnSelect?: boolean;
storage?: Storage;
popoverProps?: Partial<PopoverProps>;
}

const Root = styled(MuiButtonGroup, {
name: "CometAdminSplitButton",
slot: "root",
overridesResolver(_, styles) {
return [styles.root];
},
})();

const ActiveButton = styled(Button, {
name: "CometAdminSplitButton",
slot: "activeButton",
overridesResolver(_, styles) {
return [styles.activeButton];
},
})();

const Popover = styled(MuiPopover, {
name: "CometAdminSplitButton",
slot: "popover",
overridesResolver(_, styles) {
return [styles.popover];
},
})();

const MenuList = styled(MuiMenuList, {
name: "CometAdminSplitButton",
slot: "menuList",
overridesResolver(_, styles) {
return [styles.menuList];
},
})();

const MenuItem = styled(MuiMenuItem, {
name: "CometAdminSplitButton",
slot: "menuItem",
overridesResolver(_, styles) {
return [styles.menuItem];
},
})();

// Based on https://v4.mui.com/components/button-group/#split-button
const SplitBtn = ({
selectIcon = <ChevronDown />,
selectedIndex,
onSelectIndex,
children,
showSelectButton,
localStorageKey,
storage,
autoClickOnSelect = true,
popoverProps,
...restProps
}: PropsWithChildren<SplitButtonProps>) => {
export function SplitButton(inProps: PropsWithChildren<SplitButtonProps>) {
const {
selectIcon = <ChevronDown />,
selectedIndex,
onSelectIndex,
children,
showSelectButton,
localStorageKey,
storage,
autoClickOnSelect = true,
slotProps,
...restProps
} = useThemeProps({ props: inProps, name: "CometAdminSplitButton" });

const [showSelectButtonState, setShowSelectButtonState] = React.useState<boolean | undefined>(undefined);

const childrenArray = React.Children.toArray(children);
Expand Down Expand Up @@ -76,36 +135,38 @@ const SplitBtn = ({
const showSelect = showSelectButtonState != null ? showSelectButtonState : showSelectButton;
return (
<SplitButtonContext.Provider value={{ setShowSelectButton: setShowSelectButtonState }}>
<ButtonGroup variant={activeChildVariant} color={activeChildColor} {...restProps} ref={anchorRef}>
<Root variant={activeChildVariant} color={activeChildColor} {...restProps} {...slotProps?.root} ref={anchorRef}>
{ActiveChild}
{(showSelect ?? childrenArray.length > 1) && (
<Button
<ActiveButton
variant={activeChildVariant}
color={activeChildColor}
size="small"
classes={ActiveChild.props.classes}
onClick={handleToggle}
{...slotProps?.activeButton}
>
{selectIcon}
</Button>
</ActiveButton>
)}
</ButtonGroup>
</Root>
<Popover
open={open}
anchorEl={anchorRef.current}
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
transformOrigin={{ vertical: "top", horizontal: "center" }}
onClose={handleClose}
{...popoverProps}
{...slotProps?.popover}
>
<MenuList>
<MenuList {...slotProps?.menuList}>
{childrenArray.map((child: React.ReactElement, index) => {
return (
<MenuItem
key={index}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index, child)}
disabled={child.props.disabled}
{...slotProps?.menuItem}
>
{child.props.children}
</MenuItem>
Expand All @@ -115,9 +176,7 @@ const SplitBtn = ({
</Popover>
</SplitButtonContext.Provider>
);
};

export const SplitButton = withStyles({}, { name: "CometAdminSplitButton" })(SplitBtn);
}

declare module "@mui/material/styles" {
interface ComponentsPropsList {
Expand Down
2 changes: 1 addition & 1 deletion packages/admin/admin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export { DeleteButton, DeleteButtonClassKey, DeleteButtonProps } from "./common/
export { OkayButton, OkayButtonClassKey, OkayButtonProps } from "./common/buttons/okay/OkayButton";
export { SaveButton, SaveButtonProps } from "./common/buttons/save/SaveButton";
export { SaveButtonClassKey } from "./common/buttons/save/SaveButton.styles";
export { SplitButton, SplitButtonProps } from "./common/buttons/split/SplitButton";
export { SplitButton, SplitButtonClassKey, SplitButtonProps } from "./common/buttons/split/SplitButton";
export { SplitButtonContext, SplitButtonContextOptions } from "./common/buttons/split/SplitButtonContext";
export { useSplitButtonContext } from "./common/buttons/split/useSplitButtonContext";
export { ClearInputAdornment, ClearInputAdornmentProps } from "./common/ClearInputAdornment";
Expand Down