Skip to content

Commit 62c9a10

Browse files
authored
Merge pull request #60 from BeeInventor/develop
v1.6.0
2 parents 338b8e4 + e15d1e1 commit 62c9a10

11 files changed

+289
-4
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@beeinventor/dasiot-react-component-lib",
3-
"version": "1.5.1",
3+
"version": "1.6.0",
44
"module": "lib/index.js",
55
"types": "lib/index.d.ts",
66
"files": [

src/components/Dropdown/Dropdown.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const list: DropDownItem[] = [
3030
];
3131

3232
export default {
33-
title: 'Components/Dropdown',
33+
title: 'Components/Dropdown/Dropdown',
3434
component: Dropdown,
3535
argTypes: {
3636
onSelect: { action: 'onSelected' },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React from 'react';
2+
import { styled } from '@mui/material';
3+
import { Meta, Story } from '@storybook/react';
4+
5+
import theme from '../../../theme';
6+
7+
import StatusDropdown, { StatusDropdownProps } from './StatusDropdown';
8+
9+
export default {
10+
title: 'Components/Dropdown/StatusDropdown',
11+
component: StatusDropdown,
12+
argTypes: {
13+
onSelect: { action: 'onSelected' },
14+
},
15+
parameters: {
16+
backgrounds: { default: 'light' },
17+
},
18+
} as Meta;
19+
20+
const Block = styled('div')`
21+
display: flex;
22+
flex-direction: column;
23+
gap: 8px;
24+
& > div {
25+
display: flex;
26+
gap: 8px;
27+
}
28+
`;
29+
30+
const statusMap: StatusDropdownProps['statusMap'] = {
31+
open: {
32+
color: '#fff',
33+
bgColor: theme.color.green.$100,
34+
displayName: 'open',
35+
},
36+
inProgress: {
37+
color: '#fff',
38+
bgColor: theme.color.primary.$80,
39+
displayName: 'in progress',
40+
},
41+
completed: {
42+
color: '#fff',
43+
bgColor: theme.color.secondary.$100,
44+
displayName: 'completed',
45+
},
46+
suspend: {
47+
color: '#fff',
48+
bgColor: theme.color.secondary.$60,
49+
displayName: 'suspend',
50+
},
51+
};
52+
53+
const Template: Story<StatusDropdownProps> = (args) => (
54+
<Block>
55+
<div>
56+
<StatusDropdown {...args} defaultStatus="open" />
57+
<StatusDropdown {...args} defaultStatus="open" disabled />
58+
</div>
59+
<div>
60+
<StatusDropdown {...args} defaultStatus="inProgress" />
61+
<StatusDropdown {...args} defaultStatus="inProgress" disabled />
62+
</div>
63+
<div>
64+
<StatusDropdown {...args} defaultStatus="completed" />
65+
<StatusDropdown {...args} defaultStatus="completed" disabled />
66+
</div>
67+
<div>
68+
<StatusDropdown {...args} defaultStatus="suspend" />
69+
<StatusDropdown {...args} defaultStatus="suspend" disabled />
70+
</div>
71+
</Block>
72+
);
73+
74+
export const Default: Story<StatusDropdownProps> = Template.bind({});
75+
76+
Default.args = {
77+
statusMap,
78+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import React, { HTMLAttributes, useEffect, useRef, useState } from 'react';
2+
import {
3+
styled,
4+
Popper as MuiPopper,
5+
PopperProps,
6+
Paper as MuiPaper,
7+
ClickAwayListener,
8+
} from '@mui/material';
9+
10+
import ArrowDown from '../../../svg/ArrowDown';
11+
12+
interface ContainerProps extends HTMLAttributes<HTMLButtonElement> {
13+
color?: React.CSSProperties['color'];
14+
bgColor?: React.CSSProperties['backgroundColor'];
15+
disabled?: boolean;
16+
}
17+
18+
const shouldForwardProp = (propName: PropertyKey) => {
19+
return propName !== 'color' && propName !== 'bgColor';
20+
};
21+
22+
const Container = styled('button', { shouldForwardProp })<ContainerProps>`
23+
cursor: pointer;
24+
display: inline-flex;
25+
align-items: center;
26+
min-width: 120px;
27+
text-transform: uppercase;
28+
font-size: 1rem;
29+
line-height: 1.5;
30+
font-weight: 500;
31+
border-radius: 4px;
32+
color: ${({ color }) => color ?? '#fff'};
33+
padding: 0 10px 0 26px;
34+
background-color: ${({ bgColor, theme }) =>
35+
bgColor ?? theme.color.secondary.$60};
36+
border: none;
37+
38+
&:disabled {
39+
opacity: 0.3;
40+
pointer-events: none;
41+
}
42+
`;
43+
44+
const Popper = styled(MuiPopper)`
45+
&.MuiPopper-root {
46+
z-index: 1;
47+
}
48+
`;
49+
50+
const Paper = styled(MuiPaper)`
51+
& > ul {
52+
list-style: none;
53+
padding: 0;
54+
margin: 0;
55+
& > li {
56+
padding: 5px;
57+
}
58+
}
59+
`;
60+
61+
interface ItemProps {
62+
color?: React.CSSProperties['color'];
63+
}
64+
65+
const Item = styled('div')<ItemProps>`
66+
cursor: pointer;
67+
text-transform: uppercase;
68+
color: ${({ theme }) => theme.color.secondary.$60};
69+
padding: 5.5px 8px;
70+
border-radius: 4px;
71+
72+
&.selected {
73+
color: ${({ theme }) => theme.color.secondary.$100};
74+
pointer-events: none;
75+
}
76+
77+
&:hover {
78+
color: ${({ theme }) => theme.color.secondary.$100};
79+
background-color: ${({ theme }) => theme.color.box_bbg};
80+
}
81+
82+
&::before {
83+
display: inline-block;
84+
content: '';
85+
width: 14px;
86+
height: 14px;
87+
border-radius: 4px;
88+
background-color: ${({ color, theme }) =>
89+
color ?? theme.color.secondary.$60};
90+
margin-right: 17px;
91+
}
92+
`;
93+
94+
export interface StatusDropdownProps {
95+
defaultStatus?: string;
96+
statusMap: {
97+
[status: string]: {
98+
color?: React.CSSProperties['color'];
99+
bgColor?: React.CSSProperties['backgroundColor'];
100+
displayName: string;
101+
};
102+
};
103+
disabled?: boolean;
104+
popperProps?: PopperProps;
105+
onSelect?: (status: string) => void;
106+
}
107+
108+
const StatusDropdown: React.FC<StatusDropdownProps> = ({
109+
defaultStatus,
110+
statusMap,
111+
disabled,
112+
popperProps,
113+
onSelect,
114+
}) => {
115+
const entries = Object.entries(statusMap);
116+
const [status, setStatus] = useState(defaultStatus ?? entries[0][0]);
117+
const [open, setOpen] = useState(false);
118+
const buttonRef = useRef<HTMLButtonElement | null>(null);
119+
120+
useEffect(() => {
121+
if (defaultStatus) {
122+
setStatus(defaultStatus);
123+
}
124+
}, [defaultStatus]);
125+
126+
return (
127+
<>
128+
<Container
129+
ref={buttonRef}
130+
color={statusMap[status].color}
131+
bgColor={statusMap[status].bgColor}
132+
onClick={() => setOpen(!open)}
133+
disabled={disabled}
134+
>
135+
{statusMap[status].displayName}
136+
<ArrowDown />
137+
</Container>
138+
<Popper
139+
open={open}
140+
anchorEl={buttonRef.current}
141+
placement="bottom-start"
142+
disablePortal
143+
popperOptions={{
144+
modifiers: [
145+
{
146+
name: 'offset',
147+
options: {
148+
offset: [0, 8],
149+
},
150+
},
151+
],
152+
}}
153+
{...popperProps}
154+
>
155+
<ClickAwayListener onClickAway={() => setOpen(false)}>
156+
<Paper>
157+
<ul>
158+
{entries.map(([key, value]) => {
159+
return (
160+
<li
161+
key={`status-item-${key}`}
162+
onClick={() => {
163+
setStatus(key);
164+
setOpen(false);
165+
onSelect?.(key);
166+
}}
167+
>
168+
<Item
169+
className={`${key === status ? 'selected' : ''}`}
170+
color={value.bgColor}
171+
>
172+
{value.displayName}
173+
</Item>
174+
</li>
175+
);
176+
})}
177+
</ul>
178+
</Paper>
179+
</ClickAwayListener>
180+
</Popper>
181+
</>
182+
);
183+
};
184+
185+
export default StatusDropdown;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './StatusDropdown';

src/components/SearchTextField/SearchTextField.tsx renamed to src/components/TextField/SearchTextField/SearchTextField.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Box, styled } from '@mui/material';
22
import React from 'react';
33

44
import { SearchTextFieldProps } from './SearchTextField.type';
5-
import SearchSvgIcon from '../../svg/SearchSvgIcon';
5+
import SearchSvgIcon from '../../../svg/SearchSvgIcon';
66

77
const Container = styled(Box)`
88
display: inline-flex;

src/components/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ export { default as DropdownV2 } from './Dropdown/DropdownV2';
99
export { default as DropdownColor } from './Dropdown/DropdownColor';
1010
export { default as DatePicker } from './DatePicker';
1111
export { default as Step } from './Step';
12-
export { default as SearchTextField } from './SearchTextField';
12+
export { default as SearchTextField } from './TextField/SearchTextField';
1313
export { default as OrgText } from './OrgText';
14+
export { default as StatusDropdown } from './Dropdown/StatusDropdown';

src/svg/ArrowDown.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react';
2+
import { SVGProps } from 'react';
3+
4+
const ArrowDown: React.FC = (props: SVGProps<SVGSVGElement>) => (
5+
<svg
6+
xmlns="http://www.w3.org/2000/svg"
7+
width={32}
8+
height={32}
9+
fill="none"
10+
{...props}
11+
>
12+
<path
13+
fill="currentColor"
14+
fillRule="evenodd"
15+
d="M12.407 13.393a1 1 0 0 0-1.414 1.414l4.2 4.2a1.002 1.002 0 0 0 1.414 0l4.2-4.2a1 1 0 0 0-1.414-1.414L15.9 16.886l-3.493-3.493Z"
16+
clipRule="evenodd"
17+
/>
18+
</svg>
19+
);
20+
export default ArrowDown;

0 commit comments

Comments
 (0)