Skip to content

Commit b9854b6

Browse files
committed
feat(Providers): Add Selection provider
1 parent 3fa4b09 commit b9854b6

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

docs/styleguide.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ module.exports = {
110110
components: () => [
111111
'../react/providers/Alert',
112112
'../react/providers/Breakpoints',
113-
'../react/providers/CozyTheme'
113+
'../react/providers/CozyTheme',
114+
'../react/providers/Selection'
114115
]
115116
},
116117
{

react/providers/Selection/Readme.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
```jsx
2+
import DemoProvider from 'cozy-ui/docs/components/DemoProvider'
3+
import SelectionProvider, { useSelection } from 'cozy-ui/transpiled/react/providers/Selection'
4+
import Button from 'cozy-ui/transpiled/react/Buttons'
5+
import Icon from 'cozy-ui/transpiled/react/Icon'
6+
import Typography from 'cozy-ui/transpiled/react/Typography'
7+
import DeviceLaptopIcon from 'cozy-ui/transpiled/react/Icons/DeviceLaptop'
8+
9+
const Component = () => {
10+
const { selectedItemsId, addSelectedItem, removeSelectedItem } = useSelection()
11+
12+
return (
13+
<>
14+
<Typography>selectedItemsId : {JSON.stringify(selectedItemsId)}</Typography>
15+
<Button label="Add Item" onClick={() => addSelectedItem({ _id: '01' })} />
16+
<Button label="Remove Item" onClick={() => removeSelectedItem({ _id: '01' })} />
17+
</>
18+
)
19+
}
20+
21+
;
22+
23+
<DemoProvider>
24+
<SelectionProvider>
25+
<Component />
26+
</SelectionProvider>
27+
</DemoProvider>
28+
```

react/providers/Selection/index.jsx

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import isEqual from 'lodash/isEqual'
2+
import React, { createContext, useContext, useState } from 'react'
3+
4+
const SelectionContext = createContext()
5+
6+
export const useSelection = () => {
7+
const context = useContext(SelectionContext)
8+
9+
if (!context) {
10+
throw new Error('useSelection must be used within a SelectionProvider')
11+
}
12+
return context
13+
}
14+
15+
/**
16+
* This provider allows you to manage item selection
17+
*/
18+
const SelectionProvider = ({ children }) => {
19+
const [selectedItemsId, setSelectedItemsId] = useState([])
20+
21+
const isSelectedItem = item => {
22+
return selectedItemsId.some(selectedItemId => selectedItemId === item._id)
23+
}
24+
25+
const isSelectionEnabled = selectedItemsId.length > 0
26+
27+
const addSelectedItem = item => {
28+
setSelectedItemsId(prev => [...prev, item._id])
29+
}
30+
31+
const removeSelectedItem = item => {
32+
setSelectedItemsId(prev => prev.filter(el => el !== item._id))
33+
}
34+
35+
const toggleSelectedItem = item => {
36+
if (isSelectedItem(item)) {
37+
removeSelectedItem(item)
38+
} else {
39+
addSelectedItem(item)
40+
}
41+
}
42+
43+
const selectAll = items => {
44+
const ids = items.map(item => item._id)
45+
setSelectedItemsId(ids)
46+
}
47+
48+
const unselectAll = () => {
49+
setSelectedItemsId([])
50+
}
51+
52+
const isSelectedAllItems = items => {
53+
const a = selectedItemsId.sort()
54+
const b = items.map(item => item._id).sort()
55+
return isEqual(a, b)
56+
}
57+
58+
const toggleSelectAllItems = items => {
59+
if (isSelectedAllItems(items)) {
60+
unselectAll()
61+
} else {
62+
selectAll(items)
63+
}
64+
}
65+
66+
return (
67+
<SelectionContext.Provider
68+
value={{
69+
selectedItemsId,
70+
addSelectedItem,
71+
removeSelectedItem,
72+
toggleSelectedItem,
73+
selectAll,
74+
toggleSelectAllItems,
75+
isSelectedItem,
76+
isSelectionEnabled,
77+
isSelectedAllItems
78+
}}
79+
>
80+
{children}
81+
</SelectionContext.Provider>
82+
)
83+
}
84+
85+
export default React.memo(SelectionProvider)

0 commit comments

Comments
 (0)