Skip to content
This repository was archived by the owner on Jul 28, 2024. It is now read-only.

Commit c6bb1f5

Browse files
committed
feat: implement multiselect
1 parent aa861f5 commit c6bb1f5

File tree

11 files changed

+412
-67
lines changed

11 files changed

+412
-67
lines changed

src/woly/atoms/list/index.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ interface ListElementsProps {
1111

1212
interface ListItemProps {
1313
as?: 'a' | 'li';
14+
className?: string;
1415
disabled?: boolean;
15-
selected?: boolean;
1616
href?: string;
17-
tabIndex?: number;
17+
id?: string;
1818
onClick?: (e: React.SyntheticEvent<HTMLElement>) => void;
19-
className?: string;
19+
selected?: boolean;
20+
tabIndex?: number;
2021
}
2122

2223
const mapContainer = (properties: { columns: number } & Priority) => ({
@@ -28,6 +29,7 @@ const mapItem = (properties: ListItemProps & Priority) => ({
2829
'data-priority': properties.priority || 'secondary',
2930
'data-type': properties.as,
3031
'data-selected': properties.selected,
32+
'data-id': properties.id,
3133
});
3234

3335
export const ListContainer = styled.div.attrs(mapContainer)`
@@ -44,26 +46,28 @@ export const ListContainer = styled.div.attrs(mapContainer)`
4446

4547
export const ListItem: React.FC<ListItemProps & ListElementsProps & Priority> = ({
4648
as,
49+
className = '',
4750
disabled = false,
4851
href,
4952
iconLeft,
5053
iconRight,
54+
id,
55+
onClick,
5156
priority = 'secondary',
57+
selected = false,
5258
tabIndex,
5359
text,
54-
selected = false,
55-
className = '',
56-
onClick,
5760
}) => (
5861
<ListItemContainer
5962
as={as}
60-
href={href}
63+
className={className}
6164
disabled={disabled}
65+
href={href}
66+
id={id}
67+
onClick={onClick}
68+
priority={priority}
6269
selected={selected}
6370
tabIndex={disabled ? -1 : tabIndex}
64-
priority={priority}
65-
className={className}
66-
onClick={onClick}
6771
>
6872
{iconLeft && <span data-element="icon">{iconLeft}</span>}
6973
<span>{text}</span>
@@ -79,6 +83,7 @@ const ListItemContainer = styled.div.attrs(mapItem)`
7983
--local-icon-color: var(--woly-canvas-text-default);
8084
--local-backgound: var(--woly-canvas-default);
8185
--local-color: var(--woly-canvas-text-default);
86+
display: flex;
8287
8388
color: var(--local-color);
8489
font-size: var(--woly-font-size);
@@ -91,6 +96,7 @@ const ListItemContainer = styled.div.attrs(mapItem)`
9196
cursor: pointer;
9297
9398
span {
99+
flex: 1;
94100
svg > path {
95101
fill: var(--local-icon-color);
96102
}

src/woly/elements/input-container/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface InputContainerProps extends React.InputHTMLAttributes<HTMLInputElement
99
className?: string;
1010
disabled?: boolean;
1111
leftIcon?: React.ReactNode;
12+
onClick?: React.EventHandler<React.SyntheticEvent>;
1213
rightIcon?: React.ReactNode;
1314
}
1415

@@ -17,6 +18,7 @@ const InputContainerBase: React.FC<InputContainerProps & Priority> = ({
1718
className,
1819
disabled = 'false',
1920
leftIcon,
21+
onClick,
2022
priority = 'secondary',
2123
rightIcon,
2224
}) => (
@@ -25,6 +27,7 @@ const InputContainerBase: React.FC<InputContainerProps & Priority> = ({
2527
className={className}
2628
data-disabled={disabled}
2729
data-priority={priority}
30+
onClick={onClick}
2831
>
2932
{leftIcon && (
3033
<span data-element="icon" data-box-role="icon">

src/woly/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './atoms';
22
export * from './molecules';
3+
export * from './organisms';
34
export * from './templates';
45
export { WolyGlobalStyles } from './woly-global-styles';

src/woly/molecules/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ export { Accordion } from './accordion';
22
export { Checkbox } from './checkbox';
33
export { DataTable, DataTableColumn, HeadProps as DataTableHeadProps } from './data-table';
44
export { Field } from './field';
5+
export { InputChip } from './input-chip';
56
export { InputPassword } from './input-password';
6-
export { Notification } from './notification';
77
export { Modal } from './modal';
8+
export { Notification } from './notification';
89
export { Popover } from './popover';
910
export { RadioButton } from './radio-button';
1011
export { Select } from './select';
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React from 'react';
2+
import styled, { StyledComponent } from 'styled-components';
3+
import { ButtonIcon, Chip } from 'ui/atoms';
4+
import { IconClose } from 'static/icons';
5+
import { InputContainer, InputElement } from 'ui/elements';
6+
import { Priority } from 'lib/types';
7+
8+
type MultiSelectOptions = React.OptionHTMLAttributes<HTMLOptionElement>;
9+
10+
interface InputChipProps {
11+
className?: string;
12+
disabled: boolean;
13+
leftIcon: React.ReactNode;
14+
name?: string;
15+
onBlur?: (value?: unknown) => void;
16+
onChange?: React.EventHandler<React.SyntheticEvent>;
17+
onChipClose: React.EventHandler<React.SyntheticEvent>;
18+
onClick: React.EventHandler<React.SyntheticEvent>;
19+
onFocus?: (value?: unknown) => void;
20+
options: Array<MultiSelectOptions>;
21+
rightIcon: React.ReactNode;
22+
}
23+
24+
export const InputChipBase: React.FC<InputChipProps & Priority> = ({
25+
className,
26+
disabled = false,
27+
leftIcon,
28+
name = 'multiselect-input',
29+
onBlur,
30+
onChange,
31+
onChipClose,
32+
onClick,
33+
onFocus,
34+
options = [],
35+
priority = 'secondary',
36+
rightIcon,
37+
}) => {
38+
if (!options) {
39+
return null;
40+
}
41+
42+
let inputField = <InputElement onChange={() => {}} name={name} type="text" disabled />;
43+
44+
if (onChange) {
45+
inputField = <InputElement onChange={onChange} name={name} type="text" />;
46+
}
47+
48+
return (
49+
<InputContainer
50+
className={className}
51+
leftIcon={leftIcon}
52+
rightIcon={rightIcon}
53+
disabled={disabled}
54+
onClick={onClick}
55+
priority={priority}
56+
>
57+
{options.map(({ id, label }) => (
58+
<div key={id} data-element="input-chip">
59+
<Chip
60+
key={id}
61+
text={label}
62+
priority={priority}
63+
rightIcon={
64+
<ButtonIcon
65+
data-id={id}
66+
icon={<IconClose />}
67+
onClick={onChipClose}
68+
priority={priority}
69+
/>
70+
}
71+
/>
72+
</div>
73+
))}
74+
<div>{inputField}</div>
75+
</InputContainer>
76+
);
77+
};
78+
79+
export const InputChip = styled(InputChipBase)`
80+
[data-element='input'] {
81+
display: flex;
82+
}
83+
[data-element='input-chip'] {
84+
--woly-component-level: 0;
85+
margin: 0 3px 3px 0;
86+
}
87+
` as StyledComponent<'div', Record<string, unknown>, InputChipProps & Priority>;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {InputChip} from 'ui';
2+
import {Playground, StateEvent} from 'dev/playground';
3+
import {IconArrowDown} from 'static/icons';
4+
5+
export const fruits = [
6+
{
7+
id: 2,
8+
text: "orange",
9+
selected: false
10+
},
11+
{
12+
id: 1,
13+
text: "apple",
14+
selected: false
15+
},
16+
{
17+
id: 3,
18+
text: "lemon",
19+
selected: false
20+
}
21+
];
22+
23+
### Example
24+
25+
<Playground>
26+
<div style={{ height: '250px' }}>
27+
<StateEvent initial={null} change={(event) => event?.target?.dataset.value}>
28+
{(value, change) => (
29+
<div style={{ width: '100%' }}>
30+
<InputChip options={fruits} isInput={false} onChipClose={change} />
31+
</div>
32+
)}
33+
</StateEvent>
34+
</div>
35+
</Playground>
36+
37+
### Example 2
38+
39+
<Playground>
40+
<div style={{ height: '250px' }}>
41+
<StateEvent initial={null} change={(event) => event?.target?.dataset.value}>
42+
{(value, change) => (
43+
<div style={{ width: '100%' }}>
44+
<InputChip options={fruits} isInput={true} onChipClose={change} />
45+
</div>
46+
)}
47+
</StateEvent>
48+
</div>
49+
</Playground>

0 commit comments

Comments
 (0)