Skip to content

Commit

Permalink
Add FilterButton, label prop to Searchbar (#53)
Browse files Browse the repository at this point in the history
* Add Label to Searchbar and improve Menu component (#50)

* Add Filter Button (#51)

* Fix FilterButton hover UI (#52)
  • Loading branch information
KhubaibQaiser authored Aug 3, 2022
1 parent 561bb62 commit 25579a1
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 32 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gudangada/design-system",
"version": "0.1.29",
"version": "0.1.32",
"description": "Gada Design System",
"main": "lib/index.js",
"module": "lib/index.esm.js",
Expand Down
28 changes: 28 additions & 0 deletions src/assets/icons/FilterIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react";
import { iIconProps } from "./types";
import useIconStyles from "./useIconStyles";

const FilterIcon: React.VFC<iIconProps> = ({
width = "24",
height = "24",
color,
}) => {
const { iconColor } = useIconStyles({ color });

return (
<svg
width={width}
height={height}
viewBox="0 0 12 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.3333 0H0.666667C0.489856 0 0.320287 0.0760476 0.195262 0.211413C0.070238 0.346779 0 0.530374 0 0.72181V2.5913C0 2.96881 0.142 3.33982 0.388667 3.60689L4 7.51693V12.9926C4.00013 13.1156 4.02925 13.2365 4.0846 13.3439C4.13995 13.4512 4.2197 13.5416 4.3163 13.6062C4.41289 13.6709 4.52314 13.7079 4.6366 13.7135C4.75006 13.7192 4.86298 13.6934 4.96467 13.6386L7.63133 12.195C7.85733 12.0723 8 11.8225 8 11.549V7.51693L11.6113 3.60689C11.858 3.33982 12 2.96881 12 2.5913V0.72181C12 0.530374 11.9298 0.346779 11.8047 0.211413C11.6797 0.0760476 11.5101 0 11.3333 0ZM6.862 6.70778C6.79997 6.7747 6.75078 6.85424 6.71726 6.94182C6.68373 7.0294 6.66654 7.1233 6.66667 7.2181V11.1029L5.33333 11.8247V7.2181C5.33346 7.1233 5.31627 7.0294 5.28274 6.94182C5.24922 6.85424 5.20003 6.7747 5.138 6.70778L1.33333 2.5913V1.44362H10.6673L10.6687 2.58625L6.862 6.70778Z"
fill={iconColor}
/>
</svg>
);
};

export default FilterIcon;
1 change: 1 addition & 0 deletions src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export { default as LogoutIcon } from "./LogoutIcon";
export { default as CampaignIcon } from "./CampaignIcon";
export { default as RedemptionIcon } from "./RedemptionIcon";
export { default as SettingsIcon } from "./SettingsIcon";
export { default as FilterIcon } from "./FilterIcon";
export * from "./ExpandIcon";
export * from "./types";
41 changes: 41 additions & 0 deletions src/components/core/FilterButton/FilterButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from "react";
import { Meta, Story } from "@storybook/react";
import FilterButtonUI from "./FilterButton";
import { iFilterButtonProps } from "./types";
import { Col } from "../../core";
import { iMenuItemProps } from "../../navigation";

export default {
title: "Components/Core",
component: FilterButtonUI,
args: {
activeFilters: 2,
},
} as Meta<iFilterButtonProps>;

const navItems: iMenuItemProps[] = [
{
label: "Menu Item 1",
onClick: () => alert("Menu Item 1"),
},
{
label: "Menu Item 2",
onClick: () => alert("Menu Item 2"),
},
];

//👇 We create a “template” of how args map to rendering
const Template: Story<iFilterButtonProps> = (props) => {
return (
<Col fullHeight>
<FilterButtonUI
{...props}
buttonProps={{ className: "self-start" }}
menuProps={{ menuItems: navItems }}
/>
</Col>
);
};

//👇 Each story then reuses that template
export const FilterButton = Template.bind({});
70 changes: 70 additions & 0 deletions src/components/core/FilterButton/FilterButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as React from "react";
import { FilterIcon } from "../../../assets";
import { Menu } from "../../navigation";
import { StyledFilterButton } from "./styles";
import { iFilterButtonProps } from "./types";

const FilterButton: React.FC<iFilterButtonProps> = ({
activeFilters,
menuProps,
buttonProps,
children,
}) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};

const handleClose = () => {
setAnchorEl(null);
};

const menuItems = React.useMemo(() => {
return menuProps?.menuItems?.map((menuItem) => ({
...menuItem,
onClick: (e: React.MouseEvent<HTMLLIElement, MouseEvent>) => {
menuItem.onClick?.(e);
handleClose();
},
}));
}, [menuProps?.menuItems]);

const isFilterActive = activeFilters > 0;

return (
<>
<StyledFilterButton
variant="fab"
color="primary"
onClick={handleClick}
startIcon={<FilterIcon color={isFilterActive ? "white" : "primary"} />}
isActive={isFilterActive}
{...buttonProps}
>
Filter {activeFilters ? `(${activeFilters})` : ""}
</StyledFilterButton>

<Menu
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
anchorEl={anchorEl}
open={open}
handleClose={handleClose}
{...menuProps}
menuItems={menuItems}
>
{children}
</Menu>
</>
);
};

export default FilterButton;
1 change: 1 addition & 0 deletions src/components/core/FilterButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as FilterButton } from "./FilterButton";
20 changes: 20 additions & 0 deletions src/components/core/FilterButton/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import styled from "@emotion/styled";
import { buttonClasses } from "@mui/material";
import { Button } from "../Button";

export const StyledFilterButton = styled(Button)<{ isActive: boolean }>(
({ isActive, theme: { palette } }) => ({
[`&.${buttonClasses.root}>*`]: {
color: `${palette.interface.teal[900]} !important`,
},
[`&.${buttonClasses.root}`]: {
backgroundColor: isActive
? palette.interface.teal[100]
: palette.interface.white,
border: `1px solid ${palette.interface.teal[700]}`,
},
[`&.${buttonClasses.root}:hover`]: {
backgroundColor: palette.interface.teal[50],
},
})
);
8 changes: 8 additions & 0 deletions src/components/core/FilterButton/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { iMenuProps } from "../../navigation/Menu";
import { iButtonProps } from "../Button";

export interface iFilterButtonProps {
activeFilters: number;
buttonProps?: Partial<iButtonProps>;
menuProps?: Partial<iMenuProps>;
}
1 change: 1 addition & 0 deletions src/components/core/Searchbar/Searchbar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const Template: Story<iSearchbarProps> = (props) => {
return (
<SearchbarUI
{...props}
label="Search label"
value={value}
onChangeValue={handleChange}
onClickCancel={handleReset}
Expand Down
56 changes: 31 additions & 25 deletions src/components/core/Searchbar/Searchbar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Box, FormControl, IconButton, InputAdornment } from "@mui/material";
import * as React from "react";
import { CrossCircleIcon, SearchIcon } from "../../../assets";
import { Label } from "../../inputs";
import { Col } from "../Col";
import { StyledOutlinedInput } from "./styles";
import { iSearchbarProps } from "./types";

Expand All @@ -11,6 +13,7 @@ const Searchbar: React.VFC<iSearchbarProps> = (props) => {
onClickCancel,
onChangeValue,
size = "default",
label,
...rest
} = props;

Expand All @@ -24,32 +27,35 @@ const Searchbar: React.VFC<iSearchbarProps> = (props) => {
};

return (
<FormControl variant="outlined" {...formControlProps}>
<StyledOutlinedInput
{...rest}
size={size === "default" ? undefined : "small"}
onChange={(event) => onChangeValue(event.target.value)}
startAdornment={
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
}
inputRef={inputRef}
endAdornment={
withEndAdornment && (
<InputAdornment position="end" style={{ paddingRight: 0 }}>
{props.value ? (
<IconButton onClick={handleClickCancel}>
<CrossCircleIcon />
</IconButton>
) : (
<Box width={48} />
)}
<Col spacing={8}>
{label && <Label>{label}</Label>}
<FormControl variant="outlined" {...formControlProps}>
<StyledOutlinedInput
{...rest}
size={size === "default" ? undefined : "small"}
onChange={(event) => onChangeValue(event.target.value)}
startAdornment={
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
)
}
/>
</FormControl>
}
inputRef={inputRef}
endAdornment={
withEndAdornment && (
<InputAdornment position="end" style={{ paddingRight: 0 }}>
{props.value ? (
<IconButton onClick={handleClickCancel}>
<CrossCircleIcon />
</IconButton>
) : (
<Box width={48} />
)}
</InputAdornment>
)
}
/>
</FormControl>
</Col>
);
};

Expand Down
1 change: 1 addition & 0 deletions src/components/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./Col";
export * from "./Row";
export * from "./Divider";
export * from "./Chip";
export * from "./FilterButton";
2 changes: 1 addition & 1 deletion src/components/inputs/AutoComplete/styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from "@emotion/styled";
import { outlinedInputClasses } from "@mui/material";
import { Col } from "../../core";
import { Col } from "../../core/Col";

export const StyledAutoCompleteContainer = styled(Col)<{ isError?: boolean }>(
({ theme: { palette }, isError }) => ({
Expand Down
13 changes: 9 additions & 4 deletions src/components/navigation/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { Menu as MuiMenu } from "@mui/material";
import { iMenuProps } from "./types";
import MenuItem from "./MenuItem";

const Menu: React.VFC<iMenuProps> = ({
const Menu: React.FC<iMenuProps> = ({
menuItems,
children,
handleClose,
...menuProps
}) => {
Expand All @@ -18,12 +19,16 @@ const Menu: React.VFC<iMenuProps> = ({
vertical: "top",
horizontal: "center",
}}
BackdropProps={{ style: { opacity: 0.01 } }}
PaperProps={{ elevation: 1 }}
{...menuProps}
onClose={handleClose}
>
{menuItems.map((menuItem) => {
return <MenuItem key={menuItem.label} {...menuItem} />;
})}
{menuItems
? menuItems.map((menuItem) => {
return <MenuItem key={menuItem.label} {...menuItem} />;
})
: children}
</MuiMenu>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/navigation/Menu/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export interface iMenuItemProps {
}

export interface iMenuProps extends MenuProps {
menuItems: iMenuItemProps[];
menuItems?: iMenuItemProps[];
handleClose: VoidFunction;
}

1 comment on commit 25579a1

@vercel
Copy link

@vercel vercel bot commented on 25579a1 Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.