Skip to content

Commit d2d3a60

Browse files
committed
Change logic for one more click option
1 parent 4a32bd0 commit d2d3a60

File tree

3 files changed

+104
-89
lines changed

3 files changed

+104
-89
lines changed

example/Dropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const Dropdown: React.FC<Props> = ({onSelect, value}) => {
4343
}
4444

4545
const options = useMemo(() => {
46-
return items.filter(item => item.name.includes(inputValue));
46+
return items.filter(item => item.name.toLowerCase().includes(inputValue.toLowerCase()));
4747
}, [inputValue])
4848

4949
const {

example/MultiSelect/MultiSelect.tsx

Lines changed: 95 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React, {ChangeEvent, KeyboardEvent, useMemo, useState} from 'react';
2-
import ReactDOM from 'react-dom';
31
import classNames from 'classnames';
4-
import {useDropdown} from '../../src';
2+
import React, { ChangeEvent, KeyboardEvent, useMemo, useState } from 'react';
3+
import { useDropdown } from '../../src';
54
import './MultiSelect.css';
65

76
export type Item = {
@@ -12,62 +11,63 @@ export type Item = {
1211
type Props = {
1312
onSelect: (items: Item[]) => void;
1413
values?: Item[];
15-
}
14+
};
1615

1716
const items: Item[] = [
1817
{
1918
name: 'NewYork',
20-
value: 'NewYork'
19+
value: 'NewYork',
2120
},
2221
{
2322
name: 'Moscow',
24-
value: 'Moscow'
23+
value: 'Moscow',
2524
},
2625
{
2726
name: 'London',
28-
value: 'London'
27+
value: 'London',
2928
},
3029
{
3130
name: 'Amsterdam',
32-
value: 'Amsterdam'
31+
value: 'Amsterdam',
3332
},
3433
{
3534
name: 'Tokyo',
36-
value: 'Tokyo'
35+
value: 'Tokyo',
3736
},
3837
{
3938
name: 'Toronto',
40-
value: 'Toronto'
39+
value: 'Toronto',
4140
},
4241
{
4342
name: 'Cape Town',
44-
value: 'Cape Town'
43+
value: 'Cape Town',
4544
},
4645
{
4746
name: 'Rio de Janeiro',
48-
value: 'Rio de Janeiro'
47+
value: 'Rio de Janeiro',
4948
},
5049
];
5150

52-
53-
54-
export const Dropdown: React.FC<Props> = ({onSelect, values}) => {
51+
export const Dropdown: React.FC<Props> = ({ onSelect, values }) => {
5552
const [inputValue, setInputValue] = useState<string>('');
5653
const [selectedOptions, setSelected] = useState<Item[]>(values);
54+
const [isFocused, setFocused] = useState<Boolean>(false);
5755

5856
const handleSelect = (item: Item) => {
59-
if (selectedOptions.some(el => el.value === item.value)) {
60-
return;
57+
let newOptions = [];
58+
if (selectedOptions.some((el) => el.value === item.value)) {
59+
newOptions = selectedOptions.filter((el) => el.value !== item.value);
60+
} else {
61+
newOptions = [...selectedOptions, item];
6162
}
6263

63-
const newArr = [...selectedOptions, item];
64-
setSelected(newArr);
65-
onSelect(newArr);
66-
}
64+
setSelected(newOptions);
65+
onSelect(newOptions);
66+
};
6767

6868
const options = useMemo(() => {
69-
return items.filter(item => item.name.includes(inputValue));
70-
}, [inputValue])
69+
return items.filter((item) => item.name.toLowerCase().includes(inputValue.toLowerCase()));
70+
}, [inputValue]);
7171

7272
const {
7373
isOpen,
@@ -77,7 +77,7 @@ export const Dropdown: React.FC<Props> = ({onSelect, values}) => {
7777
getMenuProps,
7878
getItemProps,
7979
setOpen,
80-
} = useDropdown<Item>({items: options, onSelect: handleSelect})
80+
} = useDropdown<Item>({ items: options, onSelect: handleSelect });
8181

8282
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
8383
setOpen(true);
@@ -91,61 +91,80 @@ export const Dropdown: React.FC<Props> = ({onSelect, values}) => {
9191
setOpen(true);
9292
break;
9393
}
94-
}
95-
96-
const handleBlur = () => {
97-
setInputValue('');
98-
}
94+
};
9995

10096
const handleCloseClick = (item: Item) => (event) => {
10197
event.stopPropagation();
102-
const newArr = selectedOptions.filter(el => el.value !== item.value);
98+
const newArr = selectedOptions.filter((el) => el.value !== item.value);
10399
setSelected(newArr);
104100
onSelect(newArr);
105-
}
106-
107-
return <div className='wrapper' {...getWrapperProps()} onKeyDown={handleKeyDown} onBlur={handleBlur}>
108-
109-
{selectedOptions.length === 0 ? null :
110-
selectedOptions.map((item: Item) => {
111-
return (
112-
<div className='multivalue' key={item.value}>
113-
<span className='multivalue-name'>{item.name}</span>
114-
<button type='button' className='remove' onClick={handleCloseClick(item)} aria-label={`Remove value ${item.name}`}></button>
115-
</div>)
116-
})
117-
}
101+
};
118102

119-
<input
120-
className='input'
121-
type="text" id="input" {...getInputProps()}
122-
placeholder='Select city'
123-
value={inputValue}
124-
onChange={handleChange}
125-
autoComplete='off'
126-
/>
127-
128-
{isOpen &&
129-
<ul className='menu' {...getMenuProps() as any}>
130-
{options.length === 0 ?
131-
<li>No data</li>
132-
: options.map(
133-
(item: Item, index) =>
134-
<li
135-
key={item.value}
136-
className={
137-
classNames('item', {
138-
'active': highlightedIndex === index,
139-
'selected': selectedOptions.some(el => el.value === item.value),
140-
})
141-
}
142-
{...getItemProps(item, index)}
143-
>
144-
{item.name}
145-
</li>
146-
)
147-
}
148-
</ul>
149-
}
150-
</div>
151-
}
103+
const handleBlur = () => {
104+
setInputValue('');
105+
setFocused(false);
106+
};
107+
108+
const handleFocus = () => {
109+
setFocused(true);
110+
};
111+
112+
return (
113+
<div
114+
className="wrapper"
115+
{...getWrapperProps()}
116+
onKeyDown={handleKeyDown}
117+
onFocus={handleFocus}
118+
onBlur={handleBlur}
119+
>
120+
{selectedOptions.length === 0
121+
? null
122+
: selectedOptions.map((item: Item) => {
123+
return (
124+
<div className="multivalue" key={item.value}>
125+
<span className="multivalue-name">{item.name}</span>
126+
<button
127+
type="button"
128+
className="remove"
129+
onClick={handleCloseClick(item)}
130+
tabIndex={isFocused ? 0 : -1}
131+
aria-label={`Remove value ${item.name}`}
132+
></button>
133+
</div>
134+
);
135+
})}
136+
137+
<input
138+
className="input"
139+
type="text"
140+
id="input"
141+
{...getInputProps()}
142+
placeholder="Select city"
143+
value={inputValue}
144+
onChange={handleChange}
145+
autoComplete="off"
146+
/>
147+
148+
{isOpen && (
149+
<ul className="menu" {...(getMenuProps() as any)}>
150+
{options.length === 0 ? (
151+
<li>No data</li>
152+
) : (
153+
options.map((item: Item, index) => (
154+
<li
155+
key={item.value}
156+
className={classNames('item', {
157+
active: highlightedIndex === index,
158+
selected: selectedOptions.some((el) => el.value === item.value),
159+
})}
160+
{...getItemProps(item, index)}
161+
>
162+
{item.name}
163+
</li>
164+
))
165+
)}
166+
</ul>
167+
)}
168+
</div>
169+
);
170+
};

stories/Multiselect.stories.tsx

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
1-
import React, { useState } from 'react';
2-
31
import { Meta } from '@storybook/react';
4-
2+
import React, { useState } from 'react';
53
import { Dropdown, Item } from '../example/MultiSelect/MultiSelect';
64

75
export default {
86
title: 'Components/Dropdown',
97
component: Dropdown,
108
} as Meta;
119

12-
13-
1410
export const MultiSelect = () => {
1511
const [values, setValues] = useState<Item[]>([]);
1612

1713
const onSelect = (items: Item[]) => {
1814
setValues(items);
19-
}
15+
};
2016

2117
return (
22-
<>
23-
<Dropdown onSelect={onSelect} values={values} />
24-
{values.map(item => item.name + ' ')}
25-
</>);
26-
}
27-
18+
<>
19+
<Dropdown onSelect={onSelect} values={values} />
20+
{values.map((item) => item.name + ' ')}
21+
</>
22+
);
23+
};

0 commit comments

Comments
 (0)