diff --git a/docs/styleguide.config.js b/docs/styleguide.config.js
index 2875aedd2f..26cea62b13 100644
--- a/docs/styleguide.config.js
+++ b/docs/styleguide.config.js
@@ -136,6 +136,8 @@ module.exports = {
{
name: 'Special',
components: () => [
+ '../react/Alert/index.jsx',
+ '../react/AlertTitle/index.jsx',
'../react/Alerter/index.jsx',
'../react/AppIcon/index.jsx',
'../react/AppTile/index.jsx',
diff --git a/package.json b/package.json
index 5f2a07149b..7342e451fa 100644
--- a/package.json
+++ b/package.json
@@ -72,6 +72,7 @@
"@babel/helper-regex": "7.10.5",
"@cozy/codemods": "^1.9.0",
"@material-ui/core": "4.12.3",
+ "@material-ui/lab": "4.0.0-alpha.61",
"@semantic-release/changelog": "5.0.1",
"@semantic-release/git": "7.0.18",
"@semantic-release/npm": "9.0.1",
@@ -173,6 +174,7 @@
},
"peerDependencies": {
"@material-ui/core": ">=4.12",
+ "@material-ui/lab": ">=4.0.0-alpha.61",
"cozy-client": ">=28.1.0",
"cozy-device-helper": "^2.0.0",
"cozy-doctypes": "^1.69.0",
diff --git a/react/Alert/Readme.md b/react/Alert/Readme.md
new file mode 100644
index 0000000000..b124853525
--- /dev/null
+++ b/react/Alert/Readme.md
@@ -0,0 +1,122 @@
+```jsx
+import Alert from 'cozy-ui/transpiled/react/Alert'
+import AlertTitle from 'cozy-ui/transpiled/react/AlertTitle'
+import Button from 'cozy-ui/transpiled/react/Buttons'
+import Icon from 'cozy-ui/transpiled/react/Icon'
+import Variants from 'cozy-ui/docs/components/Variants'
+import DeviceLaptopIcon from 'cozy-ui/transpiled/react/Icons/DeviceLaptop'
+import DownloadIcon from 'cozy-ui/transpiled/react/Icons/Download'
+
+const initialVariants = [{
+ longText: false,
+ title: false,
+ block: false,
+ color: false,
+ largeIcon: false,
+ noIcon: false,
+ square: false,
+ actionOne: false,
+ actionTwo: false,
+ close: false
+}]
+
+;
+
+
+ {variant => (
+ : undefined}
+ action={(variant.actionOne || variant.actionTwo) ?
+ <>
+ {variant.actionOne &&
+ } />
+ }
+ {variant.actionTwo &&
+
+ }
+ >
+ : undefined
+ }
+ onClose={variant.close ? () => {} : undefined}
+ >
+ {variant.title && This is the title}
+ {variant.longText
+ ? content.ada.short
+ : "Get Cozy Drive for Desktop and synchronise your files safely to make them accessible at all times."
+ }
+
+ )}
+
+```
+
+### Colors
+
+```jsx
+import Alert from 'cozy-ui/transpiled/react/Alert'
+import AlertTitle from 'cozy-ui/transpiled/react/AlertTitle'
+import Button from 'cozy-ui/transpiled/react/Buttons'
+import Variants from 'cozy-ui/docs/components/Variants'
+
+const colors = ['primary', 'secondary','success', 'error', 'warning', 'info']
+const initialVariants = [{ title: true, block: false }]
+
+const makeButtonColor = color => ['primary', 'secondary'].includes(color) ? undefined : color
+
+;
+
+
+ {variant => (
+ <>
+ {colors.map(color =>
+
+
+ }
+ >
+ {variant.title &&
{color.toUpperCase()}}
+ This is a {color} alert
+
+
+ )}
+
+ {colors.map(color =>
+
+
+ }
+ >
+ {variant.title &&
{color.toUpperCase()}}
+ This is a {color} alert
+
+
+ )}
+
+ {colors.map(color =>
+
+
+ }
+ >
+ {variant.title &&
{color.toUpperCase()}}
+ This is a {color} alert
+
+
+ )}
+ >
+ )}
+
+```
diff --git a/react/Alert/index.jsx b/react/Alert/index.jsx
new file mode 100644
index 0000000000..55a579092c
--- /dev/null
+++ b/react/Alert/index.jsx
@@ -0,0 +1,113 @@
+import React, { forwardRef } from 'react'
+import PropTypes from 'prop-types'
+import cx from 'classnames'
+import MuiAlert from '@material-ui/lab/Alert'
+import { makeStyles } from '@material-ui/core/styles'
+
+import Icon from '../Icon'
+import CheckCircleIcon from '../Icons/CheckCircle'
+import WarningIcon from '../Icons/Warning'
+import WarningCircleIcon from '../Icons/WarningCircle'
+import InfoIcon from '../Icons/Info'
+
+const DEFAULT_ICON_SIZE = 16
+
+const defaultIconMapping = {
+ success: ,
+ warning: ,
+ error: ,
+ info:
+}
+
+const makeIcon = (icon, severity) => {
+ // used to remove icon
+ if (icon === false) {
+ return false
+ }
+
+ return (
+ icon ||
+ (['primary', 'secondary'].includes(severity) && ) ||
+ undefined
+ )
+}
+
+const useStyles = makeStyles({
+ message: {
+ maxWidth: ({ block, iconSize }) =>
+ block && `calc(100% - ${iconSize + 16}px)`
+ }
+})
+
+const Alert = forwardRef(
+ (
+ {
+ className,
+ icon,
+ severity,
+ block,
+ color,
+ square,
+ action,
+ variant,
+ children,
+ ...props
+ },
+ ref
+ ) => {
+ const madeSeverity = ['primary', 'secondary'].includes(severity)
+ ? 'success'
+ : severity
+ const madeIcon = makeIcon(icon, severity)
+ const iconSize = icon?.props?.size || DEFAULT_ICON_SIZE
+ const styles = useStyles({ iconSize, block })
+
+ return (
+
+ {children}
+
+ )
+ }
+)
+
+Alert.propTypes = {
+ className: PropTypes.string,
+ icon: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
+ severity: PropTypes.oneOf([
+ 'primary',
+ 'secondary',
+ 'success',
+ 'error',
+ 'warning',
+ 'info'
+ ]),
+ block: PropTypes.bool,
+ color: PropTypes.string,
+ square: PropTypes.bool,
+ variant: PropTypes.oneOf(['standard', 'outlined', 'filled'])
+}
+
+Alert.defaultProps = {
+ severity: 'primary',
+ block: false,
+ square: false,
+ variant: 'standard'
+}
+
+export default Alert
diff --git a/react/AlertTitle/Readme.md b/react/AlertTitle/Readme.md
new file mode 100644
index 0000000000..574b99839a
--- /dev/null
+++ b/react/AlertTitle/Readme.md
@@ -0,0 +1 @@
+Re-export of @material-ui. See [the official API](https://v4.mui.com/api/alert-title/).
diff --git a/react/AlertTitle/index.jsx b/react/AlertTitle/index.jsx
new file mode 100644
index 0000000000..7063c91dc6
--- /dev/null
+++ b/react/AlertTitle/index.jsx
@@ -0,0 +1,3 @@
+import MuiAlertTitle from '@material-ui/lab/AlertTitle'
+
+export default MuiAlertTitle
diff --git a/react/MuiCozyTheme/makeOverrides.js b/react/MuiCozyTheme/makeOverrides.js
index daf31bdcef..f1789fcc7f 100644
--- a/react/MuiCozyTheme/makeOverrides.js
+++ b/react/MuiCozyTheme/makeOverrides.js
@@ -1,4 +1,4 @@
-import { alpha } from '@material-ui/core/styles'
+import { alpha, lighten, darken } from '@material-ui/core/styles'
const SWITCH_BAR_WIDTH = 25
@@ -9,6 +9,60 @@ export const makeThemeOverrides = theme => {
return createOverrides(theme)
}
+const makeAlertColor = (theme, color) => {
+ const themeColorByColor = {
+ primary: theme.palette[color].main,
+ secondary: theme.palette.text.primary
+ }
+
+ // same approach as Mui, see https://github.com/mui/material-ui/blob/v4.x/packages/material-ui-lab/src/Alert/Alert.js#L28
+ return {
+ '&-standard': {
+ color: darken(themeColorByColor[color], 0.6),
+ backgroundColor: lighten(themeColorByColor[color], 0.9),
+ '& $icon': {
+ color: themeColorByColor[color]
+ }
+ },
+ '&-outlined': {
+ color: darken(themeColorByColor[color], 0.6),
+ border: `1px solid ${themeColorByColor[color]}`,
+ '& $icon': {
+ color: themeColorByColor[color]
+ }
+ },
+ '&-filled': {
+ backgroundColor: themeColorByColor[color]
+ }
+ }
+}
+
+const makeAlertInvertedColor = (theme, color) => {
+ return {
+ '&-standard': {
+ color: theme.palette.primary.main,
+ backgroundColor: theme.palette.background.default,
+ '& $icon': {
+ color: theme.palette[color].main
+ }
+ },
+ '&-outlined': {
+ color: theme.palette.primary.main,
+ border: `1px solid ${theme.palette.primary.main}`,
+ '& $icon': {
+ color: theme.palette[color].main
+ }
+ },
+ '&-filled': {
+ color: theme.palette[color].contrastText,
+ backgroundColor: theme.palette[color].main,
+ '& $icon': {
+ color: theme.palette[color].contrastText
+ }
+ }
+ }
+}
+
const makeChipStyleByColor = (theme, color) => ({
color: theme.palette.text[color] || theme.palette[color].main,
borderColor:
@@ -822,6 +876,44 @@ const makeOverrides = theme => ({
'&-info': makeChipStyleByColor(theme, 'info')
}
}
+ },
+ MuiAlert: {
+ root: {
+ padding: '8px 16px',
+ '&.cozyAlert': {
+ '&-primary': makeAlertColor(theme, 'primary'),
+ '&-secondary': makeAlertColor(theme, 'secondary')
+ },
+ '& $icon': {
+ paddingTop: '9px'
+ },
+ '&.block': {
+ flexWrap: 'wrap',
+ '& $action': {
+ display: 'block',
+ width: '100%',
+ paddingLeft: 0,
+ textAlign: 'right'
+ }
+ }
+ },
+ message: {
+ display: 'flex',
+ alignItems: 'center',
+ flexWrap: 'wrap'
+ },
+ action: {
+ marginRight: '-6px',
+ '& button[title="Close"]': {
+ color: theme.palette.text.secondary
+ }
+ }
+ },
+ MuiAlertTitle: {
+ root: {
+ width: '100%',
+ fontWeight: 'bold'
+ }
}
})
@@ -883,6 +975,20 @@ const makeInvertedOverrides = invertedTheme => {
color: invertedTheme.palette.error.main
}
}
+ },
+ MuiAlert: {
+ ...makeOverrides(invertedTheme).MuiAlert,
+ root: {
+ ...makeOverrides(invertedTheme).MuiAlert.root,
+ '&.cozyAlert': {
+ '&-primary': makeAlertInvertedColor(invertedTheme, 'primary'),
+ '&-secondary': makeAlertInvertedColor(invertedTheme, 'primary'),
+ '&-success': makeAlertInvertedColor(invertedTheme, 'success'),
+ '&-error': makeAlertInvertedColor(invertedTheme, 'error'),
+ '&-warning': makeAlertInvertedColor(invertedTheme, 'warning'),
+ '&-info': makeAlertInvertedColor(invertedTheme, 'info')
+ }
+ }
}
}
diff --git a/react/__snapshots__/examples.spec.jsx.snap b/react/__snapshots__/examples.spec.jsx.snap
index 41dc391f62..32fa2fdbe0 100644
--- a/react/__snapshots__/examples.spec.jsx.snap
+++ b/react/__snapshots__/examples.spec.jsx.snap
@@ -1,5 +1,105 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`Alert should render examples: Alert 1`] = `
+"
+
+
+
+
Get Cozy Drive for Desktop and synchronise your files safely to make them accessible at all times.
+
+
"
+`;
+
+exports[`Alert should render examples: Alert 2`] = `
+"
+
+
+
+
+
+
PRIMARY
This is a primary alert
+
+
+
+
+
+
+
+
+
SECONDARY
This is a secondary alert
+
+
+
+
+
+
+
+
+
SUCCESS
This is a success alert
+
+
+
+
+
+
+
+
+
ERROR
This is a error alert
+
+
+
+
+
+
+
+
+
WARNING
This is a warning alert
+
+
+
+
+
+
+
+
+
INFO
This is a info alert
+
+
+
+
+
"
+`;
+
exports[`AppTitle should render examples: AppTitle 1`] = `
"
Drive
@@ -107,7 +207,7 @@ exports[`Badge should render examples: Badge 1`] = `
"
`;
-exports[`Badge should render examples: Badge 2`] = `""`;
+exports[`Badge should render examples: Badge 2`] = `""`;
exports[`Banner should render examples: Banner 1`] = `
"
@@ -2399,187 +2499,187 @@ exports[`DropdownText should render examples: DropdownText 1`] = `
"
Default
-
-
-
-
-
-
-
-
-
Disabled
-
-
-
-
-
-
-
-
-
-
This is a long text without ellipsis
-