Skip to content

Commit 9e25f34

Browse files
committed
add: dropdown path
1 parent 4471341 commit 9e25f34

File tree

5 files changed

+347
-1
lines changed

5 files changed

+347
-1
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.2.6",
3+
"version": "1.2.7",
44
"module": "lib/index.js",
55
"types": "lib/index.d.ts",
66
"files": [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { Meta, Story } from '@storybook/react';
2+
import React, { useState } from 'react';
3+
import DropdownColor from './DropdownColor';
4+
import { DropDownColorItem, DropDownColorProps } from './DropdownColor.type';
5+
6+
const list: DropDownColorItem[] = [
7+
{
8+
id: 'path-a',
9+
value: 'path-a',
10+
name: 'Path A',
11+
color: '#58B99E',
12+
},
13+
{
14+
id: 'path-b',
15+
value: 'path-b',
16+
name: 'Path B',
17+
color: '#FF6B00',
18+
},
19+
{
20+
id: 'path-c',
21+
value: 'path-c',
22+
name: 'Path C',
23+
color: '#EF8C34',
24+
},
25+
{
26+
id: 'path-d',
27+
value: 'path-d',
28+
name: 'Path D',
29+
color: '#5296D5',
30+
},
31+
{
32+
id: 'path-e',
33+
value: 'path-e',
34+
name: 'Path E',
35+
color: '#B152C6',
36+
},
37+
];
38+
39+
export default {
40+
title: 'Components/DropdownColor',
41+
component: DropdownColor,
42+
argTypes: {
43+
onSelect: { action: 'onSelected' },
44+
disabled: {
45+
control: 'boolean',
46+
},
47+
className: {
48+
control: 'text',
49+
},
50+
listClassName: {
51+
control: 'text',
52+
},
53+
itemClassName: {
54+
control: 'text',
55+
},
56+
selectedId: {
57+
control: 'text',
58+
},
59+
mode: {
60+
control: 'radio',
61+
options: ['dark', 'light'],
62+
},
63+
},
64+
} as Meta;
65+
66+
export const DropdownColorDefault: Story<DropDownColorProps> = (args) => {
67+
const [selectedId, setSelectedId] = useState<string | undefined>('path-a');
68+
69+
return (
70+
<div>
71+
<DropdownColor
72+
{...args}
73+
selectedId={selectedId}
74+
onSelect={(value) => setSelectedId(value as string)}
75+
/>
76+
</div>
77+
);
78+
};
79+
80+
DropdownColorDefault.args = {
81+
mode: 'dark',
82+
list,
83+
placeholder: 'Please Select Item',
84+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
2+
import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp';
3+
import Box from '@mui/material/Box';
4+
import ClickAwayListener from '@mui/material/ClickAwayListener';
5+
import Popper from '@mui/material/Popper';
6+
import { styled } from '@mui/material/styles';
7+
import classNames from 'classnames';
8+
import React, { useEffect, useRef, useState } from 'react';
9+
import Icon from '../../Icon/Icon';
10+
import { DropDownColorItem, DropDownColorProps } from './DropdownColor.type';
11+
12+
const Root = styled(Box)(({ theme }) => ({
13+
...theme.typography.h3,
14+
minWidth: 220,
15+
userSelect: 'none',
16+
cursor: 'pointer',
17+
display: 'flex',
18+
justifyContent: 'space-between',
19+
alignItems: 'center',
20+
color: theme.color.secondary.$80,
21+
backgroundColor: '#FFF',
22+
padding: '8px 0px 8px 16px',
23+
borderRadius: 4,
24+
'&.dark': {
25+
color: 'white',
26+
backgroundColor: 'rgba(0, 0 ,0, 0.2)',
27+
},
28+
'&.Dropdown-empty': {
29+
color: theme.color.secondary.$60,
30+
'&.dark': {
31+
color: theme.color.secondary.$80,
32+
},
33+
},
34+
'&.Dropdown--disabled': {
35+
opacity: 0.3,
36+
pointerEvents: 'none',
37+
},
38+
}));
39+
40+
const List = styled(Box)(({ theme }) => ({
41+
backgroundColor: '#FFF',
42+
margin: '8px auto',
43+
borderRadius: 4,
44+
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
45+
'&.dark': {
46+
color: 'white',
47+
backgroundColor: theme.color.secondary.$100,
48+
},
49+
}));
50+
51+
interface LabelColorProps {
52+
color: string;
53+
}
54+
55+
const LabelColor = styled('span')<LabelColorProps>`
56+
margin: 0;
57+
padding: 0;
58+
width: 14px;
59+
height: 14px;
60+
border-radius: 50%;
61+
background-color: ${({ color }) => color};
62+
`;
63+
64+
interface ItemProps {
65+
selected: boolean;
66+
}
67+
68+
const Item = styled(Box, { label: 'Dropdown-item' })<ItemProps>(
69+
({ theme, selected }) => ({
70+
...theme.typography.h3,
71+
cursor: 'pointer',
72+
display: 'flex',
73+
alignItems: 'center',
74+
lineHeight: 2.5,
75+
'&:hover': {
76+
backgroundColor: 'rgba(0, 0, 0, .05)',
77+
},
78+
backgroundColor: selected ? 'rgba(0, 0, 0, .05)' : 'unset',
79+
}),
80+
);
81+
82+
const ContainerLabel = styled('div')`
83+
display: flex;
84+
align-items: center;
85+
gap: 10px;
86+
`;
87+
88+
const DropdownColor: React.VFC<DropDownColorProps> = (props) => {
89+
const {
90+
list,
91+
itemProps,
92+
placeholder,
93+
selectedId,
94+
disabled,
95+
onSelect,
96+
popperProps,
97+
selectionId,
98+
mode = 'light',
99+
...otherProps
100+
} = props;
101+
const selectRef = useRef<HTMLDivElement>(null);
102+
const [selectedItem, setSelectedItem] = useState<DropDownColorItem | null>(
103+
null,
104+
);
105+
const [isOpen, setIsOpen] = useState(false);
106+
107+
useEffect(() => {
108+
if (selectedId && selectedId !== selectedItem?.id) {
109+
for (let i = 0; i < list.length; i++) {
110+
if (selectedId === list[i].id) {
111+
setSelectedItem(list[i]);
112+
break;
113+
}
114+
}
115+
} else if (selectedId === undefined) {
116+
setSelectedItem(null);
117+
}
118+
}, [selectedId]);
119+
120+
useEffect(() => {
121+
for (let i = 0; i < list.length; i++) {
122+
if (selectedId === list[i].id) {
123+
setSelectedItem(list[i]);
124+
break;
125+
}
126+
}
127+
}, [list]);
128+
129+
const handleOnClickSelect = () => {
130+
setIsOpen(true);
131+
};
132+
133+
const handleOnClickAway = () => {
134+
setIsOpen(false);
135+
};
136+
137+
const handleOnClick = (item: DropDownColorItem) => {
138+
setIsOpen(false);
139+
onSelect(item.value, item);
140+
};
141+
142+
const items = list
143+
.filter((item) => item.id !== selectionId)
144+
.map((item) => (
145+
<Item
146+
key={`dropdown-item-${item.id}`}
147+
className="Dropdown-item"
148+
onClick={() => handleOnClick(item)}
149+
selected={selectedItem?.id === item.id}
150+
{...itemProps}
151+
>
152+
<Icon className="Dropdown-icon">
153+
<LabelColor color={item.color} />
154+
</Icon>
155+
{item.name}
156+
</Item>
157+
));
158+
159+
return (
160+
<>
161+
<Root
162+
ref={selectRef}
163+
className={classNames(
164+
'Dropdown-root',
165+
{
166+
'Dropdown-empty': !selectedId,
167+
},
168+
{
169+
'Dropdown--disabled': disabled,
170+
},
171+
{
172+
dark: mode === 'dark',
173+
light: mode === 'light',
174+
},
175+
)}
176+
onClick={handleOnClickSelect}
177+
{...otherProps}
178+
>
179+
{selectedItem?.name ? (
180+
<ContainerLabel>
181+
<LabelColor color={selectedItem?.color ?? '#000'} />
182+
{selectedItem?.name ?? placeholder}
183+
</ContainerLabel>
184+
) : (
185+
selectedItem?.name ?? placeholder
186+
)}
187+
<Icon className="Dropdown-icon">
188+
{isOpen ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
189+
</Icon>
190+
</Root>
191+
<Popper
192+
anchorEl={selectRef.current}
193+
open={isOpen}
194+
placement="bottom"
195+
{...popperProps}
196+
>
197+
<ClickAwayListener onClickAway={handleOnClickAway}>
198+
<List
199+
className={classNames({
200+
dark: mode === 'dark',
201+
light: mode === 'light',
202+
})}
203+
style={{ width: selectRef.current?.offsetWidth ?? 'auto' }}
204+
>
205+
{items}
206+
</List>
207+
</ClickAwayListener>
208+
</Popper>
209+
</>
210+
);
211+
};
212+
213+
export default DropdownColor;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { PopperProps } from '@mui/material';
2+
import { BoxProps } from '@mui/system';
3+
4+
export interface DropDownColorItem {
5+
id: string;
6+
name: string;
7+
value: string | number;
8+
color: string;
9+
}
10+
11+
export interface DropDownColorProps extends Omit<BoxProps, 'onSelect'> {
12+
/**
13+
* For adjustment item styles
14+
*/
15+
itemProps?: BoxProps;
16+
/**
17+
* Item list
18+
*/
19+
list: DropDownColorItem[];
20+
/**
21+
* Placeholder
22+
*/
23+
placeholder?: string;
24+
/**
25+
* Specify item
26+
*/
27+
selectedId?: string;
28+
/**
29+
* Trigger when select a item
30+
*/
31+
onSelect: (
32+
value: DropDownColorItem['value'],
33+
item: DropDownColorItem,
34+
) => void;
35+
/**
36+
* Disable dropdown
37+
*/
38+
disabled?: boolean;
39+
/**
40+
* Custom popper props
41+
*/
42+
popperProps?: Omit<PopperProps, 'open' | 'anchorEl'>;
43+
mode?: 'dark' | 'light';
44+
/**
45+
* filter the list out of this id
46+
*/
47+
selectionId?: string;
48+
}

src/components/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ export { default as Searchbar } from './Searchbar';
66
export { default as DialogButton } from './Button/DialogButton';
77
export { default as Dropdown } from './Dropdown';
88
export { default as DropdownV2 } from './Dropdown/DropdownV2';
9+
export { default as DropdownColor } from './Dropdown/DropdownColor/DropdownColor';
910
export { default as DatePicker } from './DatePicker';
1011
export { default as Step } from './Step';

0 commit comments

Comments
 (0)