cozy-ui 145.0.0 → 146.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.
- package/CHANGELOG.md +23 -0
- package/package.json +4 -2
- package/react/Markdown/Readme.md +15 -0
- package/react/Markdown/helpers.js +31 -0
- package/react/Markdown/helpers.spec.js +68 -0
- package/react/Markdown/index.jsx +2 -2
- package/react/MemberList/EmptyMembers.jsx +45 -0
- package/react/MemberList/MemberList.spec.jsx +48 -0
- package/react/MemberList/Readme.md +72 -0
- package/react/MemberList/index.jsx +70 -0
- package/react/MemberList/locales/de.json +8 -0
- package/react/MemberList/locales/en.json +8 -0
- package/react/MemberList/locales/es.json +8 -0
- package/react/MemberList/locales/fr.json +8 -0
- package/react/MemberList/locales/index.js +17 -0
- package/react/MemberList/locales/it.json +8 -0
- package/react/MemberList/locales/ru.json +8 -0
- package/react/MemberList/locales/vi.json +8 -0
- package/react/MemberRow/MemberAvatar.jsx +31 -0
- package/react/MemberRow/MemberAvatar.spec.jsx +26 -0
- package/react/MemberRow/MemberGroupAvatar.jsx +17 -0
- package/react/MemberRow/MemberRoleMenu.jsx +71 -0
- package/react/MemberRow/MemberRoleMenu.spec.jsx +49 -0
- package/react/MemberRow/MemberRoleMenuHeader.jsx +40 -0
- package/react/MemberRow/MemberRow.spec.jsx +39 -0
- package/react/MemberRow/MemberRowActions.jsx +56 -0
- package/react/MemberRow/Readme.md +57 -0
- package/react/MemberRow/index.jsx +112 -0
- package/react/MemberRow/locales/de.json +8 -0
- package/react/MemberRow/locales/en.json +8 -0
- package/react/MemberRow/locales/es.json +8 -0
- package/react/MemberRow/locales/fr.json +8 -0
- package/react/MemberRow/locales/index.js +17 -0
- package/react/MemberRow/locales/it.json +8 -0
- package/react/MemberRow/locales/ru.json +8 -0
- package/react/MemberRow/locales/vi.json +8 -0
- package/react/MemberRow/propTypes.js +33 -0
- package/react/MuiCozyTheme/overrides/makeDarkOverrides.js +6 -0
- package/react/MuiCozyTheme/overrides/makeLightOverrides.js +5 -0
- package/skills/cozy-ui-reference/references/components.md +9 -0
- package/transpiled/react/Markdown/helpers.d.ts +3 -0
- package/transpiled/react/Markdown/helpers.js +28 -0
- package/transpiled/react/Markdown/helpers.spec.d.ts +1 -0
- package/transpiled/react/Markdown/index.js +2 -2
- package/transpiled/react/MemberList/EmptyMembers.d.ts +2 -0
- package/transpiled/react/MemberList/EmptyMembers.js +42 -0
- package/transpiled/react/MemberList/MemberList.spec.d.ts +1 -0
- package/transpiled/react/MemberList/index.d.ts +61 -0
- package/transpiled/react/MemberList/index.js +63 -0
- package/transpiled/react/MemberList/locales/index.d.ts +16 -0
- package/transpiled/react/MemberList/locales/index.js +65 -0
- package/transpiled/react/MemberRow/MemberAvatar.d.ts +6 -0
- package/transpiled/react/MemberRow/MemberAvatar.js +34 -0
- package/transpiled/react/MemberRow/MemberAvatar.spec.d.ts +1 -0
- package/transpiled/react/MemberRow/MemberGroupAvatar.d.ts +6 -0
- package/transpiled/react/MemberRow/MemberGroupAvatar.js +21 -0
- package/transpiled/react/MemberRow/MemberRoleMenu.d.ts +45 -0
- package/transpiled/react/MemberRow/MemberRoleMenu.js +87 -0
- package/transpiled/react/MemberRow/MemberRoleMenu.spec.d.ts +1 -0
- package/transpiled/react/MemberRow/MemberRoleMenuHeader.d.ts +35 -0
- package/transpiled/react/MemberRow/MemberRoleMenuHeader.js +40 -0
- package/transpiled/react/MemberRow/MemberRow.spec.d.ts +1 -0
- package/transpiled/react/MemberRow/MemberRowActions.d.ts +45 -0
- package/transpiled/react/MemberRow/MemberRowActions.js +61 -0
- package/transpiled/react/MemberRow/index.d.ts +68 -0
- package/transpiled/react/MemberRow/index.js +102 -0
- package/transpiled/react/MemberRow/locales/index.d.ts +16 -0
- package/transpiled/react/MemberRow/locales/index.js +65 -0
- package/transpiled/react/MemberRow/propTypes.d.ts +32 -0
- package/transpiled/react/MemberRow/propTypes.js +30 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeDarkOverrides.d.ts +10 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeDarkOverrides.js +6 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightOverrides.d.ts +5 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightOverrides.js +5 -0
- package/transpiled/react/stylesheet.css +1 -1
- package/react/Tile/index.jsx +0 -98
- package/react/Tile/styles.styl +0 -122
- package/transpiled/react/Tile/index.d.ts +0 -68
- package/transpiled/react/Tile/index.js +0 -94
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import MemberRoleMenu from './MemberRoleMenu'
|
|
5
|
+
import DemoProvider from '../providers/DemoProvider'
|
|
6
|
+
|
|
7
|
+
const viewer = { value: 'viewer', label: 'Viewer' }
|
|
8
|
+
const editor = { value: 'editor', label: 'Editor' }
|
|
9
|
+
|
|
10
|
+
describe('MemberRoleMenu', () => {
|
|
11
|
+
let createRangeBackup
|
|
12
|
+
|
|
13
|
+
beforeAll(() => {
|
|
14
|
+
createRangeBackup = global.document.createRange
|
|
15
|
+
global.document.createRange = jest.fn(() => ({
|
|
16
|
+
setStart: () => {},
|
|
17
|
+
setEnd: () => {},
|
|
18
|
+
commonAncestorContainer: { nodeName: 'BODY', ownerDocument: document }
|
|
19
|
+
}))
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
afterAll(() => {
|
|
23
|
+
global.document.createRange = createRangeBackup
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const setup = roles => {
|
|
27
|
+
const onChange = jest.fn()
|
|
28
|
+
render(
|
|
29
|
+
<DemoProvider>
|
|
30
|
+
<MemberRoleMenu
|
|
31
|
+
member={{ id: 'bob', name: 'Bob' }}
|
|
32
|
+
value="editor"
|
|
33
|
+
roles={roles}
|
|
34
|
+
onChange={onChange}
|
|
35
|
+
/>
|
|
36
|
+
</DemoProvider>
|
|
37
|
+
)
|
|
38
|
+
return { onChange }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
it('does not change the role when the current one is picked', () => {
|
|
42
|
+
const { onChange } = setup([viewer, editor])
|
|
43
|
+
|
|
44
|
+
fireEvent.click(screen.getByRole('button', { name: 'Editor' }))
|
|
45
|
+
fireEvent.click(screen.getByRole('menuitem', { name: 'Editor' }))
|
|
46
|
+
|
|
47
|
+
expect(onChange).not.toHaveBeenCalled()
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useI18n } from 'twake-i18n'
|
|
3
|
+
|
|
4
|
+
import MemberAvatar from './MemberAvatar'
|
|
5
|
+
import MemberGroupAvatar from './MemberGroupAvatar'
|
|
6
|
+
import { memberPropType } from './propTypes'
|
|
7
|
+
import ActionsMenuMobileHeader from '../ActionsMenu/ActionsMenuMobileHeader'
|
|
8
|
+
import ListItemIcon from '../ListItemIcon'
|
|
9
|
+
import ListItemText from '../ListItemText'
|
|
10
|
+
|
|
11
|
+
const MemberRoleMenuHeader = ({ member }) => {
|
|
12
|
+
const { t } = useI18n()
|
|
13
|
+
const { name, avatarUrl, initials, color, isGroup, isCurrentUser } = member
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<ActionsMenuMobileHeader>
|
|
17
|
+
<ListItemIcon>
|
|
18
|
+
{isGroup ? (
|
|
19
|
+
<MemberGroupAvatar size="m" color={color} />
|
|
20
|
+
) : (
|
|
21
|
+
<MemberAvatar size="m" initials={initials} avatarUrl={avatarUrl} />
|
|
22
|
+
)}
|
|
23
|
+
</ListItemIcon>
|
|
24
|
+
<ListItemText
|
|
25
|
+
primary={
|
|
26
|
+
isCurrentUser
|
|
27
|
+
? t('MemberRow.you')
|
|
28
|
+
: name || t('MemberRow.defaultName')
|
|
29
|
+
}
|
|
30
|
+
primaryTypographyProps={{ variant: 'h6' }}
|
|
31
|
+
/>
|
|
32
|
+
</ActionsMenuMobileHeader>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
MemberRoleMenuHeader.propTypes = {
|
|
37
|
+
member: memberPropType.isRequired
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default MemberRoleMenuHeader
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { I18n, useI18n } from 'twake-i18n'
|
|
4
|
+
|
|
5
|
+
import MemberRow from '.'
|
|
6
|
+
import List from '../List'
|
|
7
|
+
import DemoProvider from '../providers/DemoProvider'
|
|
8
|
+
|
|
9
|
+
describe('MemberRow', () => {
|
|
10
|
+
it('keeps the translations of the app in the subtitle, and its own', () => {
|
|
11
|
+
const AppSubtitle = () => {
|
|
12
|
+
const { t } = useI18n()
|
|
13
|
+
return t('status')
|
|
14
|
+
}
|
|
15
|
+
render(
|
|
16
|
+
<DemoProvider>
|
|
17
|
+
<I18n lang="en" dictRequire={() => ({ status: 'Invitation sent' })}>
|
|
18
|
+
<List>
|
|
19
|
+
<MemberRow
|
|
20
|
+
member={{
|
|
21
|
+
id: 'bob',
|
|
22
|
+
name: 'Bob',
|
|
23
|
+
subtitle: <AppSubtitle />,
|
|
24
|
+
role: 'editor',
|
|
25
|
+
canRemove: true
|
|
26
|
+
}}
|
|
27
|
+
roles={[{ value: 'editor', label: 'Editor' }]}
|
|
28
|
+
onRoleChange={jest.fn()}
|
|
29
|
+
onRemove={jest.fn()}
|
|
30
|
+
/>
|
|
31
|
+
</List>
|
|
32
|
+
</I18n>
|
|
33
|
+
</DemoProvider>
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
expect(screen.queryByText('Invitation sent')).toBeInTheDocument()
|
|
37
|
+
expect(screen.queryByLabelText('Remove from sharing')).toBeInTheDocument()
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Icon, CrossCircleOutline } from '@linagora/twake-icons'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { useI18n } from 'twake-i18n'
|
|
5
|
+
|
|
6
|
+
import MemberRoleMenu from './MemberRoleMenu'
|
|
7
|
+
import { memberPropType, rolesPropType } from './propTypes'
|
|
8
|
+
import IconButton from '../IconButton'
|
|
9
|
+
import Spinner from '../Spinner'
|
|
10
|
+
import Typography from '../Typography'
|
|
11
|
+
|
|
12
|
+
const MemberRowActions = ({ member, roles, onRoleChange, onRemove }) => {
|
|
13
|
+
const { t } = useI18n()
|
|
14
|
+
const { role, canChangeRole, canRemove, removeIcon, removeLabel, isPending } =
|
|
15
|
+
member
|
|
16
|
+
const memberRoles = member.roles ?? roles
|
|
17
|
+
|
|
18
|
+
const isRoleMenuShown = canChangeRole && !isPending
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="u-flex u-flex-items-center u-g-1">
|
|
22
|
+
{isPending && <Spinner />}
|
|
23
|
+
{isRoleMenuShown ? (
|
|
24
|
+
<MemberRoleMenu
|
|
25
|
+
member={member}
|
|
26
|
+
value={role}
|
|
27
|
+
roles={memberRoles}
|
|
28
|
+
onChange={newRole => onRoleChange(member, newRole)}
|
|
29
|
+
/>
|
|
30
|
+
) : (
|
|
31
|
+
<Typography variant="body2">
|
|
32
|
+
{memberRoles.find(memberRole => memberRole.value === role)?.label}
|
|
33
|
+
</Typography>
|
|
34
|
+
)}
|
|
35
|
+
{canRemove && !isPending && (
|
|
36
|
+
<IconButton
|
|
37
|
+
onClick={() => onRemove(member)}
|
|
38
|
+
size="small"
|
|
39
|
+
className="u-ml-half"
|
|
40
|
+
aria-label={removeLabel ?? t('MemberRow.remove')}
|
|
41
|
+
>
|
|
42
|
+
<Icon icon={removeIcon ?? CrossCircleOutline} />
|
|
43
|
+
</IconButton>
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
MemberRowActions.propTypes = {
|
|
50
|
+
member: memberPropType.isRequired,
|
|
51
|
+
roles: rolesPropType.isRequired,
|
|
52
|
+
onRoleChange: PropTypes.func.isRequired,
|
|
53
|
+
onRemove: PropTypes.func.isRequired
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default MemberRowActions
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Displays a member of a sharing: avatar, name, subtitle, and on the right its role and a button to remove them. `MemberList` renders one row per member.
|
|
2
|
+
|
|
3
|
+
### Props of a member
|
|
4
|
+
|
|
5
|
+
* **id**: unique key of the member
|
|
6
|
+
* **name**: displayed name, replaced by "You" when `isCurrentUser`
|
|
7
|
+
* **subtitle**: email, status… (any node)
|
|
8
|
+
* **avatarUrl** and **initials**: picture of the member, initials when there is no picture or it fails to load
|
|
9
|
+
* **isGroup** and **color**: shows a group avatar
|
|
10
|
+
* **isOwner**: shows the "Owner" label and no action
|
|
11
|
+
* **role** and **roles**: current role, and the roles of this member when they differ from the `roles` of the row
|
|
12
|
+
* **canChangeRole**: shows the role in a menu, as text otherwise
|
|
13
|
+
* **canRemove**, **removeIcon** and **removeLabel**: remove button, its icon and its accessible label
|
|
14
|
+
* **action**: `{ label, onClick }` button shown in place of the role and the remove button
|
|
15
|
+
* **isPending**: shows a spinner instead of the actions
|
|
16
|
+
* **onClick**: makes the row clickable
|
|
17
|
+
* **data**: anything the app needs back in its callbacks, not read by the row
|
|
18
|
+
|
|
19
|
+
### Demo
|
|
20
|
+
|
|
21
|
+
```jsx
|
|
22
|
+
import DemoProvider from 'cozy-ui/docs/components/DemoProvider'
|
|
23
|
+
import List from 'cozy-ui/transpiled/react/List'
|
|
24
|
+
import MemberRow from 'cozy-ui/transpiled/react/MemberRow'
|
|
25
|
+
import { Unlink } from '@linagora/twake-icons'
|
|
26
|
+
|
|
27
|
+
const roles = [
|
|
28
|
+
{ value: 'viewer', label: 'Viewer' },
|
|
29
|
+
{ value: 'editor', label: 'Editor' }
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const rows = [
|
|
33
|
+
['Owner', { id: 'alice', name: 'Alice', subtitle: 'alice@cozy.cc', initials: 'A', isOwner: true, isCurrentUser: true }],
|
|
34
|
+
['Role and remove button', { id: 'bob', name: 'Bob', subtitle: 'bob@cozy.cc', initials: 'B', role: 'editor', canChangeRole: true, canRemove: true }],
|
|
35
|
+
['Role as text', { id: 'carol', name: 'Carol', subtitle: 'carol@cozy.cc', initials: 'C', role: 'viewer' }],
|
|
36
|
+
['Action', { id: 'dave', name: 'Dave', subtitle: 'dave@cozy.cc', initials: 'D', action: { label: 'Verify', onClick: () => {} } }],
|
|
37
|
+
['Pending', { id: 'eve', name: 'Eve', subtitle: 'eve@cozy.cc', initials: 'E', role: 'editor', canChangeRole: true, canRemove: true, isPending: true }],
|
|
38
|
+
['Clickable group with its only role', { id: 'family', name: 'Family', subtitle: '2 members', isGroup: true, role: 'editor', roles: [{ value: 'editor', label: 'Editor' }], canChangeRole: true, canRemove: true, onClick: () => {} }],
|
|
39
|
+
['Clickable group, other remove icon', { id: 'team', name: 'Team', subtitle: '3 members', isGroup: true, color: '#FF7F1B', role: 'editor', canRemove: true, removeIcon: Unlink, removeLabel: 'Unlink Team', onClick: () => {} }]
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
;
|
|
43
|
+
|
|
44
|
+
<DemoProvider>
|
|
45
|
+
<List>
|
|
46
|
+
{rows.map(([label, member]) => (
|
|
47
|
+
<MemberRow
|
|
48
|
+
key={member.id}
|
|
49
|
+
member={{ ...member, name: `${member.name} (${label})` }}
|
|
50
|
+
roles={roles}
|
|
51
|
+
onRoleChange={() => {}}
|
|
52
|
+
onRemove={() => {}}
|
|
53
|
+
/>
|
|
54
|
+
))}
|
|
55
|
+
</List>
|
|
56
|
+
</DemoProvider>
|
|
57
|
+
```
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React, { Fragment } from 'react'
|
|
3
|
+
import { useI18n, useExtendI18n } from 'twake-i18n'
|
|
4
|
+
|
|
5
|
+
import MemberAvatar from './MemberAvatar'
|
|
6
|
+
import MemberGroupAvatar from './MemberGroupAvatar'
|
|
7
|
+
import MemberRowActions from './MemberRowActions'
|
|
8
|
+
import { locales } from './locales'
|
|
9
|
+
import { memberPropType, rolesPropType } from './propTypes'
|
|
10
|
+
import Button from '../Buttons'
|
|
11
|
+
import Fade from '../Fade'
|
|
12
|
+
import ListItem from '../ListItem'
|
|
13
|
+
import ListItemIcon from '../ListItemIcon'
|
|
14
|
+
import ListItemSecondaryAction from '../ListItemSecondaryAction'
|
|
15
|
+
import ListItemText from '../ListItemText'
|
|
16
|
+
import Typography from '../Typography'
|
|
17
|
+
import useBreakpoints from '../providers/Breakpoints'
|
|
18
|
+
|
|
19
|
+
export const FADE_IN_DURATION = 600
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Displays a member of a sharing: avatar, name, subtitle, role and remove button
|
|
23
|
+
*
|
|
24
|
+
* @param {object} props
|
|
25
|
+
* @param {object} props.member - Member to display, see `memberPropType`
|
|
26
|
+
* @param {object[]} props.roles - Roles a member can get, as `{ value, label }`
|
|
27
|
+
* @param {boolean} [props.isNew] - Whether the row fades in
|
|
28
|
+
* @param {Function} props.onRoleChange - Called with the member and its new role
|
|
29
|
+
* @param {Function} props.onRemove - Called with the member to remove
|
|
30
|
+
*/
|
|
31
|
+
const MemberRow = ({ member, roles, isNew, onRoleChange, onRemove }) => {
|
|
32
|
+
useExtendI18n(locales)
|
|
33
|
+
const { t } = useI18n()
|
|
34
|
+
const { isMobile } = useBreakpoints()
|
|
35
|
+
const {
|
|
36
|
+
name,
|
|
37
|
+
subtitle,
|
|
38
|
+
avatarUrl,
|
|
39
|
+
initials,
|
|
40
|
+
color,
|
|
41
|
+
isGroup,
|
|
42
|
+
isOwner,
|
|
43
|
+
isCurrentUser,
|
|
44
|
+
action,
|
|
45
|
+
onClick
|
|
46
|
+
} = member
|
|
47
|
+
|
|
48
|
+
const ActionsWrapper = onClick ? ListItemSecondaryAction : Fragment
|
|
49
|
+
const actionsWrapperProps = onClick
|
|
50
|
+
? { className: isMobile ? 'u-mr-1' : 'u-mr-2' }
|
|
51
|
+
: undefined
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Fade in timeout={isNew ? FADE_IN_DURATION : 0}>
|
|
55
|
+
<ListItem
|
|
56
|
+
button={Boolean(onClick)}
|
|
57
|
+
onClick={onClick}
|
|
58
|
+
gutters={isMobile ? 'default' : 'double'}
|
|
59
|
+
size="small"
|
|
60
|
+
>
|
|
61
|
+
<ListItemIcon>
|
|
62
|
+
{isGroup ? (
|
|
63
|
+
<MemberGroupAvatar size="m" color={color} />
|
|
64
|
+
) : (
|
|
65
|
+
<MemberAvatar size="m" initials={initials} avatarUrl={avatarUrl} />
|
|
66
|
+
)}
|
|
67
|
+
</ListItemIcon>
|
|
68
|
+
<ListItemText
|
|
69
|
+
primary={
|
|
70
|
+
<Typography variant="body1">
|
|
71
|
+
{isCurrentUser
|
|
72
|
+
? t('MemberRow.you')
|
|
73
|
+
: name || t('MemberRow.defaultName')}
|
|
74
|
+
</Typography>
|
|
75
|
+
}
|
|
76
|
+
secondary={subtitle}
|
|
77
|
+
/>
|
|
78
|
+
<ActionsWrapper {...actionsWrapperProps}>
|
|
79
|
+
{isOwner && (
|
|
80
|
+
<Typography variant="body2">{t('MemberRow.owner')}</Typography>
|
|
81
|
+
)}
|
|
82
|
+
{action && (
|
|
83
|
+
<Button
|
|
84
|
+
style={{ position: 'initial' }} // fix z-index bug on iOS when under a BottomDrawer due to relative position
|
|
85
|
+
variant="text"
|
|
86
|
+
onClick={action.onClick}
|
|
87
|
+
label={action.label}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
{!isOwner && !action && (
|
|
91
|
+
<MemberRowActions
|
|
92
|
+
member={member}
|
|
93
|
+
roles={roles}
|
|
94
|
+
onRoleChange={onRoleChange}
|
|
95
|
+
onRemove={onRemove}
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
</ActionsWrapper>
|
|
99
|
+
</ListItem>
|
|
100
|
+
</Fade>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
MemberRow.propTypes = {
|
|
105
|
+
member: memberPropType.isRequired,
|
|
106
|
+
roles: rolesPropType.isRequired,
|
|
107
|
+
isNew: PropTypes.bool,
|
|
108
|
+
onRoleChange: PropTypes.func.isRequired,
|
|
109
|
+
onRemove: PropTypes.func.isRequired
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export default MemberRow
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import de from './de.json'
|
|
2
|
+
import en from './en.json'
|
|
3
|
+
import es from './es.json'
|
|
4
|
+
import fr from './fr.json'
|
|
5
|
+
import it from './it.json'
|
|
6
|
+
import ru from './ru.json'
|
|
7
|
+
import vi from './vi.json'
|
|
8
|
+
|
|
9
|
+
export const locales = {
|
|
10
|
+
de,
|
|
11
|
+
en,
|
|
12
|
+
es,
|
|
13
|
+
fr,
|
|
14
|
+
it,
|
|
15
|
+
ru,
|
|
16
|
+
vi
|
|
17
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
|
|
3
|
+
const rolePropType = PropTypes.shape({
|
|
4
|
+
value: PropTypes.string.isRequired,
|
|
5
|
+
label: PropTypes.string.isRequired
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
export const rolesPropType = PropTypes.arrayOf(rolePropType)
|
|
9
|
+
|
|
10
|
+
export const memberPropType = PropTypes.shape({
|
|
11
|
+
id: PropTypes.string.isRequired,
|
|
12
|
+
name: PropTypes.string,
|
|
13
|
+
subtitle: PropTypes.node,
|
|
14
|
+
avatarUrl: PropTypes.string,
|
|
15
|
+
initials: PropTypes.string,
|
|
16
|
+
color: PropTypes.string,
|
|
17
|
+
isGroup: PropTypes.bool,
|
|
18
|
+
isOwner: PropTypes.bool,
|
|
19
|
+
isCurrentUser: PropTypes.bool,
|
|
20
|
+
role: PropTypes.string,
|
|
21
|
+
roles: rolesPropType,
|
|
22
|
+
canChangeRole: PropTypes.bool,
|
|
23
|
+
canRemove: PropTypes.bool,
|
|
24
|
+
removeIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
25
|
+
removeLabel: PropTypes.string,
|
|
26
|
+
action: PropTypes.shape({
|
|
27
|
+
label: PropTypes.string.isRequired,
|
|
28
|
+
onClick: PropTypes.func.isRequired
|
|
29
|
+
}),
|
|
30
|
+
isPending: PropTypes.bool,
|
|
31
|
+
onClick: PropTypes.func,
|
|
32
|
+
data: PropTypes.any
|
|
33
|
+
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import merge from 'lodash/merge'
|
|
2
2
|
|
|
3
3
|
import { makeLightOverrides } from './makeLightOverrides'
|
|
4
|
+
import { alpha } from '../../styles'
|
|
4
5
|
|
|
5
6
|
export const makeDarkOverrides = theme => {
|
|
6
7
|
const makeOverridesForDarkTheme = theme => ({
|
|
@@ -8,6 +9,11 @@ export const makeDarkOverrides = theme => {
|
|
|
8
9
|
colorDefault: {
|
|
9
10
|
backgroundColor: theme.palette.primary.main
|
|
10
11
|
}
|
|
12
|
+
},
|
|
13
|
+
MuiBackdrop: {
|
|
14
|
+
root: {
|
|
15
|
+
backgroundColor: alpha(theme.palette.common.black, 0.5)
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
18
|
})
|
|
13
19
|
|
|
@@ -1280,6 +1280,15 @@ This component is used to render markdown content. To see more about the Markdow
|
|
|
1280
1280
|
import Markdown from 'cozy-ui/transpiled/react/Markdown'
|
|
1281
1281
|
```
|
|
1282
1282
|
|
|
1283
|
+
**Example:**
|
|
1284
|
+
|
|
1285
|
+
```jsx
|
|
1286
|
+
import { getPlainTextFromMarkdown } from 'cozy-ui/transpiled/react/Markdown/helpers'
|
|
1287
|
+
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
1288
|
+
|
|
1289
|
+
<Typography noWrap>{getPlainTextFromMarkdown(answer)}</Typography>
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1283
1292
|
|
|
1284
1293
|
### MidEllipsis
|
|
1285
1294
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import remarkGfm from 'remark-gfm';
|
|
2
|
+
import remarkParse from 'remark-parse';
|
|
3
|
+
import unified from 'unified';
|
|
4
|
+
export var remarkPlugins = [remarkGfm];
|
|
5
|
+
var markdown = unified().use(remarkParse).use(remarkPlugins); // Nodes whose children are blocks or cells: a space keeps their words apart
|
|
6
|
+
|
|
7
|
+
var BLOCKS = ['root', 'blockquote', 'list', 'listItem', 'table', 'tableRow'];
|
|
8
|
+
|
|
9
|
+
var getWords = function getWords(node) {
|
|
10
|
+
var _node$alt, _node$children;
|
|
11
|
+
|
|
12
|
+
if (node.type === 'image' || node.type === 'imageReference') return (_node$alt = node.alt) !== null && _node$alt !== void 0 ? _node$alt : '';
|
|
13
|
+
if (node.type === 'break') return ' ';
|
|
14
|
+
if (typeof node.value === 'string') return node.value;
|
|
15
|
+
return ((_node$children = node.children) !== null && _node$children !== void 0 ? _node$children : []).map(getWords).join(BLOCKS.includes(node.type) ? ' ' : '');
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Gives the words of a Markdown content on one line, without its syntax,
|
|
19
|
+
* as the Markdown component shows them: for a preview
|
|
20
|
+
*
|
|
21
|
+
* @param {string} content - Markdown content
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export var getPlainTextFromMarkdown = function getPlainTextFromMarkdown(content) {
|
|
27
|
+
return getWords(markdown.parse(content)).replace(/\s+/g, ' ').trim();
|
|
28
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -6,7 +6,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import ReactMarkdown from 'react-markdown';
|
|
9
|
-
import
|
|
9
|
+
import { remarkPlugins } from "cozy-ui/transpiled/react/Markdown/helpers";
|
|
10
10
|
import Link from "cozy-ui/transpiled/react/Link";
|
|
11
11
|
import Typography from "cozy-ui/transpiled/react/Typography";
|
|
12
12
|
|
|
@@ -44,7 +44,7 @@ var components = _objectSpread({
|
|
|
44
44
|
var Markdown = function Markdown(_ref4) {
|
|
45
45
|
var content = _ref4.content;
|
|
46
46
|
return /*#__PURE__*/React.createElement(ReactMarkdown, {
|
|
47
|
-
remarkPlugins:
|
|
47
|
+
remarkPlugins: remarkPlugins,
|
|
48
48
|
components: components
|
|
49
49
|
}, content);
|
|
50
50
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Icon, Team } from '@linagora/twake-icons';
|
|
2
|
+
import cx from 'classnames';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useI18n, useExtendI18n } from 'twake-i18n';
|
|
5
|
+
import { locales } from "cozy-ui/transpiled/react/MemberList/locales";
|
|
6
|
+
import Typography from "cozy-ui/transpiled/react/Typography";
|
|
7
|
+
import useBreakpoints from "cozy-ui/transpiled/react/providers/Breakpoints";
|
|
8
|
+
import { alpha, makeStyles } from "cozy-ui/transpiled/react/styles";
|
|
9
|
+
var useStyles = makeStyles(function (theme) {
|
|
10
|
+
return {
|
|
11
|
+
root: {
|
|
12
|
+
backgroundColor: alpha(theme.palette.secondary.main, theme.palette.action.hoverOpacity)
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
var EmptyMembers = function EmptyMembers() {
|
|
18
|
+
useExtendI18n(locales);
|
|
19
|
+
|
|
20
|
+
var _useI18n = useI18n(),
|
|
21
|
+
t = _useI18n.t;
|
|
22
|
+
|
|
23
|
+
var _useBreakpoints = useBreakpoints(),
|
|
24
|
+
isMobile = _useBreakpoints.isMobile;
|
|
25
|
+
|
|
26
|
+
var classes = useStyles();
|
|
27
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
28
|
+
className: cx('u-flex u-flex-column u-flex-items-center u-pv-2 u-ph-1 u-bdrs-6', isMobile ? 'u-mh-1' : 'u-mh-2', classes.root)
|
|
29
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
30
|
+
icon: Team,
|
|
31
|
+
size: 48,
|
|
32
|
+
color: "var(--primaryColorLight)"
|
|
33
|
+
}), /*#__PURE__*/React.createElement(Typography, {
|
|
34
|
+
variant: "body2",
|
|
35
|
+
className: "u-mt-half"
|
|
36
|
+
}, t('MemberList.empty.title')), /*#__PURE__*/React.createElement(Typography, {
|
|
37
|
+
variant: "caption",
|
|
38
|
+
color: "textSecondary"
|
|
39
|
+
}, t('MemberList.empty.subtitle')));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default EmptyMembers;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|