cozy-ui 101.2.0 → 102.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/package.json +2 -1
  3. package/react/ActionsBar/Readme.md +54 -0
  4. package/react/ActionsBar/ResponsiveAction.jsx +67 -0
  5. package/react/ActionsBar/index.jsx +190 -0
  6. package/react/ActionsBar/locales/en.json +3 -0
  7. package/react/ActionsBar/locales/fr.json +3 -0
  8. package/react/ActionsBar/locales/withActionsLocales.jsx +11 -0
  9. package/react/ActionsMenu/Actions/call.js +19 -18
  10. package/react/ActionsMenu/Actions/emailTo.js +19 -18
  11. package/react/ActionsMenu/Actions/helpers.js +166 -3
  12. package/react/ActionsMenu/Actions/index.js +1 -0
  13. package/react/ActionsMenu/Actions/locales/en.json +9 -0
  14. package/react/ActionsMenu/Actions/locales/fr.json +9 -0
  15. package/react/ActionsMenu/Actions/locales/withActionsLocales.jsx +4 -2
  16. package/react/ActionsMenu/Actions/modify.js +19 -18
  17. package/react/ActionsMenu/Actions/others.jsx +13 -0
  18. package/react/ActionsMenu/Actions/print.js +47 -43
  19. package/react/ActionsMenu/Actions/smsTo.js +19 -18
  20. package/react/ActionsMenu/Actions/viewInContacts.js +19 -19
  21. package/react/ActionsMenu/ActionsItems.jsx +34 -9
  22. package/react/ActionsMenu/ActionsMenuItem.jsx +1 -1
  23. package/react/ActionsMenu/Readme.md +5 -2
  24. package/react/ActionsMenu/index.jsx +7 -5
  25. package/react/DropdownButton/index.jsx +1 -1
  26. package/react/Icon/Readme.md +47 -59
  27. package/react/Icon/index.jsx +26 -12
  28. package/react/ListItem/ListItemBase/index.jsx +1 -1
  29. package/react/SelectionBar/Readme.md +37 -19
  30. package/react/SelectionBar/index.jsx +7 -0
  31. package/react/index.js +1 -0
  32. package/react/providers/I18n/helpers.js +33 -0
  33. package/transpiled/react/ActionsBar/ResponsiveAction.js +62 -0
  34. package/transpiled/react/ActionsBar/index.js +187 -0
  35. package/transpiled/react/ActionsBar/locales/withActionsLocales.js +12 -0
  36. package/transpiled/react/ActionsMenu/Actions/call.js +15 -12
  37. package/transpiled/react/ActionsMenu/Actions/emailTo.js +15 -12
  38. package/transpiled/react/ActionsMenu/Actions/helpers.js +413 -3
  39. package/transpiled/react/ActionsMenu/Actions/index.js +2 -1
  40. package/transpiled/react/ActionsMenu/Actions/locales/withActionsLocales.js +8 -0
  41. package/transpiled/react/ActionsMenu/Actions/modify.js +14 -11
  42. package/transpiled/react/ActionsMenu/Actions/others.js +12 -0
  43. package/transpiled/react/ActionsMenu/Actions/print.js +84 -51
  44. package/transpiled/react/ActionsMenu/Actions/smsTo.js +15 -12
  45. package/transpiled/react/ActionsMenu/Actions/viewInContacts.js +14 -11
  46. package/transpiled/react/ActionsMenu/ActionsItems.js +20 -11
  47. package/transpiled/react/ActionsMenu/ActionsMenuItem.js +1 -1
  48. package/transpiled/react/ActionsMenu/index.js +9 -6
  49. package/transpiled/react/DropdownButton/index.js +1 -1
  50. package/transpiled/react/Icon/index.js +17 -13
  51. package/transpiled/react/ListItem/ListItemBase/index.js +1 -1
  52. package/transpiled/react/SelectionBar/index.js +5 -0
  53. package/transpiled/react/index.js +2 -1
  54. package/transpiled/react/providers/I18n/helpers.js +35 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,40 @@
1
+ # [102.1.0](https://github.com/cozy/cozy-ui/compare/v102.0.0...v102.1.0) (2024-01-25)
2
+
3
+
4
+ ### Features
5
+
6
+ * **Action:** Print can now deal with multiple docs ([ee5695d](https://github.com/cozy/cozy-ui/commit/ee5695d))
7
+ * Add pdf-lib package ([9b363e1](https://github.com/cozy/cozy-ui/commit/9b363e1))
8
+
9
+ # [102.0.0](https://github.com/cozy/cozy-ui/compare/v101.2.0...v102.0.0) (2024-01-23)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **ActionsMenuItem:** Props `t`, `f`, `lang` was spread to DOM element ([3636fe3](https://github.com/cozy/cozy-ui/commit/3636fe3))
15
+ * Func `getOnlyNeededActions` wasn't dealing with `divider` as `hr` ([ec4acf6](https://github.com/cozy/cozy-ui/commit/ec4acf6))
16
+
17
+
18
+ ### Features
19
+
20
+ * **Actions:** Add `others` ([0186834](https://github.com/cozy/cozy-ui/commit/0186834))
21
+ * **ActionsBar:** Add this new component ([d80e3cf](https://github.com/cozy/cozy-ui/commit/d80e3cf))
22
+ * **ActionsItems:** Add `component` prop that manages the display ([db16d71](https://github.com/cozy/cozy-ui/commit/db16d71))
23
+ * **ActionsItems:** Add `webviewIntent` in actions ([a64595b](https://github.com/cozy/cozy-ui/commit/a64595b))
24
+ * **ActionsItems:** Spread the action to the displayed component ([a0a9aa4](https://github.com/cozy/cozy-ui/commit/a0a9aa4))
25
+ * **ActionsMenu:** Replace `doc` prop by `docs` ([1049809](https://github.com/cozy/cozy-ui/commit/1049809))
26
+ * **ActionsMenu:** Use own locales and add `getActionsI18n()` ([351595e](https://github.com/cozy/cozy-ui/commit/351595e))
27
+ * **I18n:** Add `getI18n()` that work like `useI18n` but without React ([4b65a35](https://github.com/cozy/cozy-ui/commit/4b65a35))
28
+ * **Icon:** Prop `icon` no longer required + can use Icon comp ([3bd5b9b](https://github.com/cozy/cozy-ui/commit/3bd5b9b))
29
+ * **SelectionBar:** Deprecates the component ([6e72491](https://github.com/cozy/cozy-ui/commit/6e72491))
30
+
31
+
32
+ ### BREAKING CHANGES
33
+
34
+ * **ActionsMenu:** When using ActionsMenu, we no longer imply we deal with one single document, but several documents. Who can do more can do less. Beside, `disabled` on actions is no longer a boolean but a function. So:
35
+ - on `<ActionsMenu />` replace `doc` prop by `docs` and provide an array instead of object
36
+ - on actions, `disabled` must be a func instead of a boolean
37
+
1
38
  # [101.2.0](https://github.com/cozy/cozy-ui/compare/v101.1.1...v101.2.0) (2024-01-19)
2
39
 
3
40
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "101.2.0",
3
+ "version": "102.1.0",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -171,6 +171,7 @@
171
171
  "mui-bottom-sheet": "https://github.com/cozy/mui-bottom-sheet.git#v1.0.9",
172
172
  "node-polyglot": "^2.2.2",
173
173
  "normalize.css": "^8.0.0",
174
+ "pdf-lib": "1.17.1",
174
175
  "piwik-react-router": "0.12.1",
175
176
  "react-chartjs-2": "4.1.0",
176
177
  "react-markdown": "^4.0.8",
@@ -0,0 +1,54 @@
1
+ Use same actions as `<ActionsMenu />`
2
+
3
+ ```jsx
4
+ import DemoProvider from 'cozy-ui/docs/components/DemoProvider'
5
+ import Buttons from 'cozy-ui/transpiled/react/Buttons'
6
+ import TrashIcon from 'cozy-ui/transpiled/react/Icons/Trash'
7
+ import RenameIcon from 'cozy-ui/transpiled/react/Icons/Rename'
8
+ import ShareIcon from 'cozy-ui/transpiled/react/Icons/Share'
9
+ import ActionsBar from 'cozy-ui/transpiled/react/ActionsBar'
10
+ import { makeActions, modify, emailTo, print, viewInContacts, smsTo, call } from 'cozy-ui/transpiled/react/ActionsMenu/Actions'
11
+
12
+ const selectedItem = {
13
+ _id: 1,
14
+ type: 'file'
15
+ }
16
+
17
+ const doc = {
18
+ _id: 'id01',
19
+ _type: 'io.cozy.contacts',
20
+ phone: [{ number: '0102030405' }],
21
+ email: [{ address: 'johndoe@cozy.cc' }],
22
+ }
23
+
24
+ initialState = { selected: isTesting() ? [doc, doc] : [] }
25
+
26
+ const addSelected = () => setState(previousState => {
27
+ const arr = previousState.selected
28
+ arr.push(doc)
29
+ return { selected: arr }
30
+ })
31
+
32
+ const removeSelected = () => setState(previousState => {
33
+ const arr = previousState.selected
34
+ arr.pop()
35
+ return { selected: arr }
36
+ })
37
+
38
+ const actions = makeActions([ modify, viewInContacts, call, smsTo, emailTo ])
39
+
40
+ ;
41
+
42
+ <DemoProvider>
43
+ <Buttons label="Add a selected document" className="u-mb-1-s u-mr-1" onClick={addSelected} />
44
+ <Buttons label="Remove a selected document" onClick={removeSelected} />
45
+
46
+ {state.selected.length > 0 && (
47
+ <ActionsBar
48
+ actions={actions}
49
+ docs={state.selected}
50
+ onClose={() => setState({selected: []})}
51
+ />
52
+ )}
53
+ </DemoProvider>
54
+ ```
@@ -0,0 +1,67 @@
1
+ import React, { forwardRef } from 'react'
2
+
3
+ import useBreakpoints from '../providers/Breakpoints'
4
+ import { makeStyles } from '../styles'
5
+ import Button from '../Buttons'
6
+ import Typography from '../Typography'
7
+ import Icon from '../Icon'
8
+
9
+ const useDesktopStyles = makeStyles({
10
+ root: {
11
+ border: 'none !important', // to force also on disabled status
12
+ '&:hover': {
13
+ border: 'none'
14
+ }
15
+ }
16
+ })
17
+
18
+ const useMobileStyles = makeStyles({
19
+ root: {
20
+ display: 'block',
21
+ height: '100%',
22
+ flex: '1 1 0',
23
+ padding: 0,
24
+ border: 'none !important', // to force also when disabled
25
+ '&:hover': {
26
+ border: 'none'
27
+ }
28
+ },
29
+ label: { textTransform: 'none' },
30
+ startIcon: {
31
+ marginRight: 0,
32
+ marginBottom: 2
33
+ }
34
+ })
35
+
36
+ const ResponsiveAction = forwardRef(({ action, disabled, onClick }, ref) => {
37
+ const { isMobile } = useBreakpoints()
38
+ const useStyles = isMobile ? useMobileStyles : useDesktopStyles
39
+ const styles = useStyles()
40
+
41
+ return (
42
+ <Button
43
+ ref={ref}
44
+ classes={styles}
45
+ variant="secondary"
46
+ startIcon={<Icon icon={action.icon} />}
47
+ label={
48
+ isMobile ? (
49
+ <Typography
50
+ variant="caption"
51
+ color={disabled ? 'inherit' : 'textPrimary'}
52
+ >
53
+ {action.label}
54
+ </Typography>
55
+ ) : (
56
+ action.label
57
+ )
58
+ }
59
+ disabled={disabled}
60
+ onClick={onClick}
61
+ />
62
+ )
63
+ })
64
+
65
+ ResponsiveAction.displayName = 'ResponsiveAction'
66
+
67
+ export default ResponsiveAction
@@ -0,0 +1,190 @@
1
+ import React, { useRef, useState, useMemo } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { makeStyles } from '../styles'
5
+ import useBreakpoints from '../providers/Breakpoints'
6
+ import AppBar from '../AppBar'
7
+ import Toolbar from '../Toolbar'
8
+ import Box from '../Box'
9
+ import Icon from '../Icon'
10
+ import IconButton from '../IconButton'
11
+ import CrossIcon from '../Icons/Cross'
12
+ import CrossCircleIcon from '../Icons/CrossCircle'
13
+ import DotsIcon from '../Icons/Dots'
14
+ import ActionsMenu from '../ActionsMenu'
15
+ import ActionsItems from '../ActionsMenu/ActionsItems'
16
+ import { getOnlyNeededActions } from '../ActionsMenu/Actions/helpers'
17
+ import { useI18n } from '../providers/I18n'
18
+ import { makeActions, others } from '../ActionsMenu/Actions'
19
+
20
+ import ResponsiveAction from './ResponsiveAction'
21
+ import withActionsLocales from './locales/withActionsLocales'
22
+
23
+ const useStyles = makeStyles({
24
+ appBar: ({ isMobile }) => ({
25
+ height: isMobile ? '4rem' : '3rem',
26
+ top: isMobile ? 'auto' : 0,
27
+ bottom: isMobile ? 0 : undefined,
28
+ zIndex: 'var(--zIndex-selection)',
29
+ boxShadow: isMobile ? 'var(--shadow8)' : 'var(--shadow1)'
30
+ }),
31
+ toolbar: {
32
+ height: 'inherit'
33
+ },
34
+ selectedCount: ({ isMobile }) => ({
35
+ display: 'flex',
36
+ flexShrink: 0,
37
+ position: 'relative',
38
+ height: 'inherit',
39
+ minWidth: '2rem',
40
+ alignItems: 'center',
41
+ justifyContent: 'center',
42
+ marginRight: '0.5rem',
43
+ gap: !isMobile ? '1rem' : undefined,
44
+ '&:after': {
45
+ content: '""',
46
+ display: 'block',
47
+ position: 'absolute',
48
+ right: '-0.5rem',
49
+ borderTop: '0.5rem solid transparent',
50
+ borderBottom: '0.5rem solid transparent',
51
+ borderLeft: '0.5rem solid var(--primaryColor)'
52
+ }
53
+ }),
54
+ desktopCloseButton: {
55
+ position: 'absolute',
56
+ right: 0
57
+ },
58
+ actionsContainer: {
59
+ display: 'flex',
60
+ height: '100%',
61
+ flexGrow: 1,
62
+ alignItems: 'center',
63
+ justifyContent: 'center'
64
+ }
65
+ })
66
+
67
+ const ActionsBar = ({
68
+ actions,
69
+ docs,
70
+ autoClose,
71
+ maxDesktopActions,
72
+ onClose
73
+ }) => {
74
+ const { isMobile } = useBreakpoints()
75
+ const { t } = useI18n()
76
+ const anchorRef = useRef()
77
+ const [showMenu, setShowMenu] = useState(false)
78
+ const styles = useStyles({ isMobile })
79
+
80
+ const showMobileCloseButton = !!onClose && isMobile
81
+ const showDesktopCloseButton = !!onClose && !isMobile
82
+ const maxActionsDisplayed = isMobile ? 4 : maxDesktopActions
83
+
84
+ const cleanedActions = useMemo(() => getOnlyNeededActions(actions, docs), [
85
+ actions,
86
+ docs
87
+ ])
88
+
89
+ const countActionsToDisplay =
90
+ cleanedActions.length > maxActionsDisplayed
91
+ ? maxActionsDisplayed - 1
92
+ : maxActionsDisplayed
93
+ const SLICE_INDEX = Math.max(1, countActionsToDisplay)
94
+ const barActions = cleanedActions.slice(0, SLICE_INDEX)
95
+ const menuActions = cleanedActions.slice(SLICE_INDEX)
96
+ const otherAction = makeActions([others])
97
+
98
+ const handleClick = () => {
99
+ autoClose && onClose?.()
100
+ }
101
+
102
+ return (
103
+ <AppBar className={styles.appBar} position="fixed" color="inherit">
104
+ <Toolbar
105
+ className={styles.toolbar}
106
+ variant={isMobile ? 'regular' : 'dense'}
107
+ disableGutters
108
+ >
109
+ {showDesktopCloseButton && (
110
+ <IconButton className={styles.desktopCloseButton} onClick={onClose}>
111
+ <Icon icon={CrossIcon} />
112
+ </IconButton>
113
+ )}
114
+ <Box
115
+ className={styles.selectedCount}
116
+ padding={showMobileCloseButton ? '0 1rem 0 0' : '0 1rem'}
117
+ color="primary.contrastText"
118
+ bgcolor="primary.main"
119
+ >
120
+ {showMobileCloseButton && (
121
+ <IconButton color="inherit" onClick={onClose}>
122
+ <Icon icon={CrossCircleIcon} />
123
+ </IconButton>
124
+ )}
125
+ <div>{isMobile ? docs.length : t('selected', docs.length)}</div>
126
+ </Box>
127
+ <div className={styles.actionsContainer}>
128
+ {/* actions displayed in the bar itself */}
129
+ <ActionsItems
130
+ docs={docs}
131
+ component={ResponsiveAction}
132
+ actions={barActions}
133
+ onClick={handleClick}
134
+ />
135
+
136
+ {/* actions displayed in ActionsMenu */}
137
+ {menuActions.length > 0 && (
138
+ <>
139
+ {isMobile ? (
140
+ <ActionsItems
141
+ docs={docs}
142
+ component={ResponsiveAction}
143
+ actions={otherAction}
144
+ onClick={() => setShowMenu(true)}
145
+ />
146
+ ) : (
147
+ <IconButton ref={anchorRef} onClick={() => setShowMenu(true)}>
148
+ <Icon icon={DotsIcon} />
149
+ </IconButton>
150
+ )}
151
+ <ActionsMenu
152
+ ref={anchorRef}
153
+ open={showMenu}
154
+ docs={docs}
155
+ actions={menuActions}
156
+ anchorOrigin={{
157
+ vertical: 'bottom',
158
+ horizontal: 'left'
159
+ }}
160
+ componentsProps={{
161
+ actionsItems: {
162
+ onClick: handleClick
163
+ }
164
+ }}
165
+ onClose={() => setShowMenu(false)}
166
+ />
167
+ </>
168
+ )}
169
+ </div>
170
+ </Toolbar>
171
+ </AppBar>
172
+ )
173
+ }
174
+
175
+ ActionsBar.propTypes = {
176
+ /**
177
+ * A number corresponding to the display of the maximum number of items.
178
+ * The other actions will be displayed in an additional menu.
179
+ * Only works on desktop since maximum number is forced in mobile
180
+ */
181
+ maxDesktopActions: PropTypes.number,
182
+ autoClose: PropTypes.bool
183
+ }
184
+
185
+ ActionsBar.defaultProps = {
186
+ maxDesktopActions: 5,
187
+ autoClose: true
188
+ }
189
+
190
+ export default withActionsLocales(ActionsBar)
@@ -0,0 +1,3 @@
1
+ {
2
+ "selected": "%{smart_count} item selected |||| %{smart_count} items selected"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "selected": "%{smart_count} élément sélectionné |||| %{smart_count} éléments sélectionnés"
3
+ }
@@ -0,0 +1,11 @@
1
+ import withOnlyLocales from '../../providers/I18n/withOnlyLocales'
2
+
3
+ import en from './en.json'
4
+ import fr from './fr.json'
5
+
6
+ export const locales = {
7
+ en,
8
+ fr
9
+ }
10
+
11
+ export default withOnlyLocales(locales)
@@ -1,33 +1,34 @@
1
1
  import React, { forwardRef } from 'react'
2
2
 
3
3
  import TelephoneIcon from '../../Icons/Telephone'
4
- import withActionsLocales from './locales/withActionsLocales'
4
+ import { getActionsI18n } from './locales/withActionsLocales'
5
5
  import ActionsMenuItem from '../ActionsMenuItem'
6
6
  import ListItemIcon from '../../ListItemIcon'
7
7
  import Icon from '../../Icon'
8
8
  import ListItemText from '../../ListItemText'
9
- import { useI18n } from '../../providers/I18n'
10
9
 
11
10
  export const call = () => {
11
+ const { t } = getActionsI18n()
12
+ const icon = TelephoneIcon
13
+ const label = t('call')
14
+
12
15
  return {
13
16
  name: 'call',
14
- action: doc => {
15
- const phoneNumber = doc?.phone?.[0]?.number
17
+ icon,
18
+ label,
19
+ action: docs => {
20
+ const phoneNumber = docs?.[0]?.phone?.[0]?.number
16
21
  !!phoneNumber && window.open(`tel:${phoneNumber}`, '_self')
17
22
  },
18
- Component: withActionsLocales(
19
- forwardRef((props, ref) => {
20
- const { t } = useI18n()
21
-
22
- return (
23
- <ActionsMenuItem {...props} ref={ref}>
24
- <ListItemIcon>
25
- <Icon icon={TelephoneIcon} />
26
- </ListItemIcon>
27
- <ListItemText primary={t('call')} />
28
- </ActionsMenuItem>
29
- )
30
- })
31
- )
23
+ Component: forwardRef((props, ref) => {
24
+ return (
25
+ <ActionsMenuItem {...props} ref={ref}>
26
+ <ListItemIcon>
27
+ <Icon icon={icon} />
28
+ </ListItemIcon>
29
+ <ListItemText primary={label} />
30
+ </ActionsMenuItem>
31
+ )
32
+ })
32
33
  }
33
34
  }
@@ -1,33 +1,34 @@
1
1
  import React, { forwardRef } from 'react'
2
2
 
3
3
  import EmailIcon from '../../Icons/Email'
4
- import withActionsLocales from './locales/withActionsLocales'
4
+ import { getActionsI18n } from './locales/withActionsLocales'
5
5
  import ActionsMenuItem from '../ActionsMenuItem'
6
6
  import ListItemIcon from '../../ListItemIcon'
7
7
  import Icon from '../../Icon'
8
8
  import ListItemText from '../../ListItemText'
9
- import { useI18n } from '../../I18n'
10
9
 
11
10
  export const emailTo = () => {
11
+ const { t } = getActionsI18n()
12
+ const icon = EmailIcon
13
+ const label = t('emailTo')
14
+
12
15
  return {
13
16
  name: 'emailTo',
14
- action: doc => {
15
- const emailAddress = doc?.email?.[0]?.address
17
+ icon,
18
+ label,
19
+ action: docs => {
20
+ const emailAddress = docs?.[0]?.email?.[0]?.address
16
21
  !!emailAddress && window.open(`mailto:${emailAddress}`, '_self')
17
22
  },
18
- Component: withActionsLocales(
19
- forwardRef((props, ref) => {
20
- const { t } = useI18n()
21
-
22
- return (
23
- <ActionsMenuItem {...props} ref={ref}>
24
- <ListItemIcon>
25
- <Icon icon={EmailIcon} />
26
- </ListItemIcon>
27
- <ListItemText primary={t('emailTo')} />
28
- </ActionsMenuItem>
29
- )
30
- })
31
- )
23
+ Component: forwardRef((props, ref) => {
24
+ return (
25
+ <ActionsMenuItem {...props} ref={ref}>
26
+ <ListItemIcon>
27
+ <Icon icon={icon} />
28
+ </ListItemIcon>
29
+ <ListItemText primary={label} />
30
+ </ActionsMenuItem>
31
+ )
32
+ })
32
33
  }
33
34
  }