Skip to content

Commit

Permalink
feat(menuitem): add determinate/indeterminate variant to the MenuItem (
Browse files Browse the repository at this point in the history
…#602)

* feat(menuitem): add determinate/indeterminate variant to the MenuItem component

* fix(jest): new jest config

* fix(a11y): fix storybook:axe timeouts

* fix(jest): fix jest test timeouts
  • Loading branch information
masoudmanson authored Sep 14, 2023
1 parent 60f5f60 commit 7c7e3b3
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 17 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@
"build-storybook": "storybook build -o docs-build",
"test-storybook": "test-storybook",
"storybook:axe": "yarn build-storybook && yarn storybook:axeOnly",
"storybook:axeOnly": "axe-storybook --build-dir docs-build",
"storybook:axeOnly": "axe-storybook --build-dir docs-build --timeout 10000",
"test": "lerna run test -- --detectOpenHandles",
"test:updateSnapshots": "lerna run test -- -u",
"test:updateSnapshots": "lerna run test -- -u --detectOpenHandles",
"namespace-check": "lerna run namespace-check",
"prepare": "husky install",
"lint": "lerna run lint",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
MenuItem,
MenuItemProps,
} from "@czi-sds/components";
import React from "react";
import { noop } from "src/common/utils";

const MenuNameSpaceTest = (
Expand All @@ -18,6 +17,7 @@ const MenuNameSpaceTest = (
isMultiSelect
disabled={false}
selected
sdsStyle="determinate"
>
Contact us
</MenuItem>
Expand Down
77 changes: 75 additions & 2 deletions packages/components/src/core/MenuItem/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-use-before-define */
import { Args, Meta } from "@storybook/react";
import RawMenuItem from "./index";
import RawMenuItem, { MenuItemProps } from "./index";
import { DemoWrapper } from "./style";

const MenuItem = (props: Args): JSX.Element => {
Expand Down Expand Up @@ -37,7 +37,15 @@ export default {
"flagCheck",
],
},
sdsIconProps: { control: { type: "object" } },
sdsIconProps: {
control: { type: "object" },
},
sdsStyle: {
control: {
type: "radio",
},
options: ["determinate", "indeterminate"],
},
selected: {
control: { type: "boolean" },
},
Expand All @@ -56,13 +64,19 @@ export default {
export const Default = {
args: {
column: "column value here",
disabled: false,
isMultiSelect: false,
name: "text here",
sdsIconProps: {},
sdsStyle: "determinate",
selected: false,
},
};

// Screenshot test

const MULTI_SELECT_OPTIONS = [false, true];
const SDS_STYLE_OPTIONS = ["determinate", "indeterminate"];
const COLUMN_OPTIONS = [undefined, "Column"];
/**
* (thuang): Add `as const` to make sure the type is not widened to `string`
Expand Down Expand Up @@ -229,13 +243,56 @@ const ScreenshotTestDemo = (props: Args): JSX.Element => {
<p style={LABEL_STYLE}>
Selected: <b>{selected ? "true" : "false"}</b>
</p>
{SDS_STYLE_OPTIONS.map((sdsStyle) => {
return (
<MenuItemStyles
isMultiSelect={isMultiSelect}
column={column}
sdsIcon={sdsIcon}
selected={selected}
sdsStyle={sdsStyle}
key={String(sdsStyle)}
/>
);
})}
</div>
);
}

// loop through all SDS_STYLE_OPTIONS + create headers for DITERMINISTIC_OPTIONS
function MenuItemStyles({
isMultiSelect,
column,
sdsIcon,
selected,
sdsStyle,
}: {
isMultiSelect: (typeof MULTI_SELECT_OPTIONS)[number];
column: (typeof COLUMN_OPTIONS)[number];
sdsIcon: (typeof ICON_OPTIONS)[number];
selected: (typeof SELECTED_OPTIONS)[number];
sdsStyle: (typeof SDS_STYLE_OPTIONS)[number];
}) {
const LABEL_STYLE: React.CSSProperties = {
...MID_LABEL,
alignSelf: "end",
borderWidth: "1px",
fontSize: "0.83em",
margin: "0 0 10px 0",
};
return (
<div style={DISPLAY_CONTENTS}>
<p style={LABEL_STYLE}>
SdsStyle: <b>{sdsStyle}</b>
</p>
{DISABLED_OPTIONS.map((disabled) => {
return (
<MenuItemDisabled
isMultiSelect={isMultiSelect}
column={column}
sdsIcon={sdsIcon}
selected={selected}
sdsStyle={sdsStyle as MenuItemProps<"gear">["sdsStyle"]}
disabled={disabled}
key={String(disabled)}
/>
Expand All @@ -251,12 +308,14 @@ const ScreenshotTestDemo = (props: Args): JSX.Element => {
column,
sdsIcon,
selected,
sdsStyle,
disabled,
}: {
isMultiSelect: (typeof MULTI_SELECT_OPTIONS)[number];
column: (typeof COLUMN_OPTIONS)[number];
sdsIcon: (typeof ICON_OPTIONS)[number];
selected: (typeof SELECTED_OPTIONS)[number];
sdsStyle: MenuItemProps<"gear">["sdsStyle"];
disabled: (typeof DISABLED_OPTIONS)[number];
}) {
const LEVEL_STYLE: React.CSSProperties = {
Expand Down Expand Up @@ -287,6 +346,7 @@ const ScreenshotTestDemo = (props: Args): JSX.Element => {
column={column}
sdsIcon={sdsIcon}
selected={selected}
sdsStyle={sdsStyle}
disabled={disabled}
className={`pseudo-${state}`}
key={state}
Expand Down Expand Up @@ -316,6 +376,7 @@ export const ScreenshotTest = {
"isMultiSelect",
"sdsIcon",
"sdsIconProps",
"sdsStyle",
"selected",
],
},
Expand All @@ -334,6 +395,18 @@ export const Test = {
name: "test text",
},
parameters: {
controls: {
exclude: [
"name",
"column",
"disabled",
"isMultiSelect",
"sdsIcon",
"sdsIconProps",
"sdsStyle",
"selected",
],
},
snapshot: {
skip: true,
},
Expand Down
34 changes: 26 additions & 8 deletions packages/components/src/core/MenuItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
ColumnWrapper,
ContentWrapper,
StyledCheck,
StyledCheckIconWrapper,
StyledIconWrapper,
StyledMenuItem,
StyledMenuItemIcon,
StyledMinus,
TextWrapper,
} from "./style";

Expand Down Expand Up @@ -53,6 +54,7 @@ export interface MenuItemExtraProps<
isMultiSelect?: boolean;
sdsIcon?: IconName;
sdsIconProps?: Partial<IconProps<IconName>>;
sdsStyle?: "determinate" | "indeterminate";
}

export type MenuItemProps<IconName extends keyof IconNameToSmallSizes> =
Expand All @@ -72,23 +74,39 @@ const MenuItem = forwardRef(function MenuItem<
isMultiSelect = false,
sdsIcon,
sdsIconProps,
sdsStyle = "determinate",
...originalMenuItemProps
} = props;
const { selected = false } = originalMenuItemProps as MenuItemProps<IconName>;

return (
<StyledMenuItem {...originalMenuItemProps} disabled={disabled} ref={ref}>
{isMultiSelect && (
// TODO (mlila): replace with sds InputCheckbox class once complete
<StyledCheckIconWrapper>
const selectionIcon = () => {
if (sdsStyle === "determinate") {
return (
<StyledIconWrapper>
<StyledCheck
className="check-icon"
selected={selected}
color="primary"
disabled={disabled}
/>
</StyledCheckIconWrapper>
)}
</StyledIconWrapper>
);
}
return (
<StyledIconWrapper>
<StyledMinus
className="check-icon"
selected={selected}
color="primary"
disabled={disabled}
/>
</StyledIconWrapper>
);
};

return (
<StyledMenuItem {...originalMenuItemProps} disabled={disabled} ref={ref}>
{isMultiSelect && selectionIcon()}

<ContentWrapper>
<TextWrapper
Expand Down
29 changes: 25 additions & 4 deletions packages/components/src/core/MenuItem/style.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Check } from "@mui/icons-material";
import { Check, Remove } from "@mui/icons-material";
import { MenuItem, menuItemClasses } from "@mui/material";
import { styled } from "@mui/material/styles";
import { CommonThemeProps } from "../styles";
Expand Down Expand Up @@ -191,12 +191,12 @@ export const DemoWrapper = styled("div")`
width: 250px;
`;

interface StyledCheckType {
interface StyledIconType {
selected?: boolean;
disabled?: boolean;
}

export const StyledCheckIconWrapper = styled("span")`
export const StyledIconWrapper = styled("span")`
${(props) => {
const spacings = getSpaces(props);
const iconSizes = getIconSizes(props);
Expand All @@ -212,7 +212,28 @@ export const StyledCheckIconWrapper = styled("span")`

export const StyledCheck = styled(Check, {
shouldForwardProp: (prop) => prop !== "selected",
})<StyledCheckType>`
})<StyledIconType>`
${(props) => {
const { selected, disabled } = props;
const colors = getColors(props);
const iconSizes = getIconSizes(props);
const selectedColor = disabled ? colors?.gray[300] : colors?.primary[400];
return `
color: ${selected ? selectedColor : "transparent"};
padding: 0;
height: ${iconSizes?.s.height}px;
width: ${iconSizes?.s.width}px;
&.MuiCheckbox-colorPrimary.Mui-checked:hover {
background-color: transparent;
}
`;
}}
`;

export const StyledMinus = styled(Remove, {
shouldForwardProp: (prop) => prop !== "selected",
})<StyledIconType>`
${(props) => {
const { selected, disabled } = props;
const colors = getColors(props);
Expand Down

0 comments on commit 7c7e3b3

Please sign in to comment.