cozy-ui 130.9.0 → 130.10.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 CHANGED
@@ -1,3 +1,12 @@
1
+ # [130.10.0](https://github.com/cozy/cozy-ui/compare/v130.9.0...v130.10.0) (2025-10-16)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add EditBadge component ([47e98d2](https://github.com/cozy/cozy-ui/commit/47e98d2))
7
+ * **EditBadge:** We can now pass props to the main Badge component ([98eb169](https://github.com/cozy/cozy-ui/commit/98eb169))
8
+ * **Utils/React:** Add `AddPropsToChildren` function ([1724619](https://github.com/cozy/cozy-ui/commit/1724619))
9
+
1
10
  # [130.9.0](https://github.com/cozy/cozy-ui/compare/v130.8.1...v130.9.0) (2025-10-16)
2
11
 
3
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "130.9.0",
3
+ "version": "130.10.0",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -0,0 +1,102 @@
1
+ import React, { useRef } from 'react'
2
+
3
+ import { handleDelete, handleUpload } from './helpers'
4
+ import { locales } from './locales'
5
+ import Icon from '../Icon'
6
+ import CameraIcon from '../Icons/Camera'
7
+ import TrashIcon from '../Icons/Trash'
8
+ import ListItemIcon from '../ListItemIcon'
9
+ import ListItemText from '../ListItemText'
10
+ import Menu from '../Menu'
11
+ import MenuItem from '../MenuItem'
12
+ import { useAlert } from '../providers/Alert'
13
+ import { useI18n, useExtendI18n } from '../providers/I18n'
14
+
15
+ const EditMenu = ({
16
+ anchorRef,
17
+ status,
18
+ showMenu,
19
+ setShowMenu,
20
+ setStatus,
21
+ setTimestamp,
22
+ onUpload,
23
+ onDelete
24
+ }) => {
25
+ useExtendI18n(locales)
26
+ const { t } = useI18n()
27
+ const { showAlert } = useAlert()
28
+
29
+ const fileInputRef = useRef(null)
30
+
31
+ return (
32
+ <>
33
+ <input
34
+ className="u-dn"
35
+ type="file"
36
+ ref={fileInputRef}
37
+ accept="image/*"
38
+ onChange={event =>
39
+ handleUpload({
40
+ event,
41
+ t,
42
+ fileInputRef,
43
+ status,
44
+ onUpload,
45
+ setStatus,
46
+ setTimestamp,
47
+ setShowMenu,
48
+ showAlert
49
+ })
50
+ }
51
+ />
52
+ {showMenu && (
53
+ <Menu
54
+ open
55
+ anchorEl={anchorRef}
56
+ getContentAnchorEl={null}
57
+ anchorOrigin={{
58
+ vertical: 'bottom',
59
+ horizontal: 'left'
60
+ }}
61
+ transformOrigin={{
62
+ vertical: 'top',
63
+ horizontal: 'left'
64
+ }}
65
+ onClose={() => setShowMenu(false)}
66
+ >
67
+ <MenuItem
68
+ onClick={() => {
69
+ setShowMenu(false)
70
+ fileInputRef.current.click() // triggers onChange of the input
71
+ }}
72
+ >
73
+ <ListItemIcon>
74
+ <Icon icon={CameraIcon} />
75
+ </ListItemIcon>
76
+ <ListItemText primary={t('EditBadge.menu.update')} />
77
+ </MenuItem>
78
+ <MenuItem
79
+ onClick={() =>
80
+ handleDelete({
81
+ t,
82
+ status,
83
+ onDelete,
84
+ setShowMenu,
85
+ setStatus,
86
+ setTimestamp,
87
+ showAlert
88
+ })
89
+ }
90
+ >
91
+ <ListItemIcon>
92
+ <Icon icon={TrashIcon} />
93
+ </ListItemIcon>
94
+ <ListItemText primary={t('EditBadge.menu.delete')} />
95
+ </MenuItem>
96
+ </Menu>
97
+ )}
98
+ </>
99
+ )
100
+ }
101
+
102
+ export default EditMenu
@@ -0,0 +1,22 @@
1
+ ⚠️ Must be used within `AlertProvider`.
2
+
3
+ ```jsx
4
+ import DemoProvider from 'cozy-ui/docs/components/DemoProvider'
5
+ import AlertProvider from 'cozy-ui/transpiled/react/providers/Alert'
6
+ import EditBadge from 'cozy-ui/transpiled/react/EditBadge'
7
+ import Avatar from 'cozy-ui/transpiled/react/Avatar'
8
+
9
+ ;
10
+
11
+ <DemoProvider>
12
+ <AlertProvider>
13
+ <EditBadge
14
+ src={timestamp => ""}
15
+ onUpload={file => {}}
16
+ onDelete={() => {}}
17
+ >
18
+ <Avatar size={94} alt="Avatar" />
19
+ </EditBadge>
20
+ </AlertProvider>
21
+ </DemoProvider>
22
+ ```
@@ -0,0 +1,32 @@
1
+ import cx from 'classnames'
2
+ import React from 'react'
3
+
4
+ import Spinner from '../Spinner'
5
+ import { AddPropsToChildren } from '../utils/react'
6
+
7
+ const StatusWrapper = ({ src, status, setStatus, timestamp, children }) => {
8
+ if (status === 'LOADING') {
9
+ return (
10
+ <>
11
+ {AddPropsToChildren(children, childProps => ({
12
+ className: cx(childProps.className, 'u-o-50')
13
+ }))}
14
+ <Spinner className="u-m-0" middle size="large" />
15
+ </>
16
+ )
17
+ }
18
+
19
+ if (status === 'PRESENT') {
20
+ return AddPropsToChildren(children, () => ({
21
+ key: timestamp,
22
+ src,
23
+ onError: () => setStatus('ABSENT')
24
+ }))
25
+ }
26
+
27
+ return AddPropsToChildren(children, () => ({
28
+ key: timestamp
29
+ }))
30
+ }
31
+
32
+ export default StatusWrapper
@@ -0,0 +1,102 @@
1
+ const MAX_FILE_SIZE = 5 * 1024 * 1024
2
+ const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
3
+
4
+ export const handleUpload = async ({
5
+ event,
6
+ t,
7
+ fileInputRef,
8
+ status,
9
+ onUpload,
10
+ setStatus,
11
+ setTimestamp,
12
+ setShowMenu,
13
+ showAlert
14
+ }) => {
15
+ const file = event.target.files[0]
16
+ if (!file) return
17
+
18
+ if (file.size > MAX_FILE_SIZE) {
19
+ showAlert({
20
+ message: t('EditBadge.upload.file-size'),
21
+ severity: 'error'
22
+ })
23
+ return
24
+ }
25
+
26
+ if (!ALLOWED_TYPES.includes(file.type)) {
27
+ showAlert({
28
+ message: t('EditBadge.upload.file-type'),
29
+ severity: 'error'
30
+ })
31
+ return
32
+ }
33
+
34
+ const controller = new AbortController()
35
+ const timeoutId = setTimeout(() => controller.abort(), 30000)
36
+
37
+ const previouStatus = status
38
+ setStatus('LOADING')
39
+
40
+ try {
41
+ await onUpload(file)
42
+ clearTimeout(timeoutId)
43
+
44
+ const newTimestamp = Date.now()
45
+ setStatus('PRESENT')
46
+ setTimestamp(newTimestamp)
47
+ showAlert({
48
+ message: t('EditBadge.upload.success'),
49
+ severity: 'success'
50
+ })
51
+ } catch (error) {
52
+ clearTimeout(timeoutId)
53
+ setStatus(previouStatus)
54
+ showAlert({
55
+ message: t('EditBadge.upload.error'),
56
+ severity: 'error'
57
+ })
58
+ } finally {
59
+ setShowMenu(false)
60
+ if (fileInputRef.current) {
61
+ fileInputRef.current.value = ''
62
+ }
63
+ }
64
+ }
65
+
66
+ export const handleDelete = async ({
67
+ t,
68
+ status,
69
+ onDelete,
70
+ setShowMenu,
71
+ setStatus,
72
+ setTimestamp,
73
+ showAlert
74
+ }) => {
75
+ setShowMenu(false)
76
+
77
+ const controller = new AbortController()
78
+ const timeoutId = setTimeout(() => controller.abort(), 30000)
79
+ const previousStatus = status
80
+ setStatus('LOADING')
81
+
82
+ try {
83
+ await onDelete()
84
+ clearTimeout(timeoutId)
85
+
86
+ const checkTimestamp = Date.now()
87
+
88
+ setStatus('ABSENT')
89
+ setTimestamp(checkTimestamp)
90
+ showAlert({
91
+ message: t('EditBadge.delete.success'),
92
+ severity: 'success'
93
+ })
94
+ } catch (error) {
95
+ clearTimeout(timeoutId)
96
+ setStatus(previousStatus)
97
+ showAlert({
98
+ message: t('EditBadge.delete.error'),
99
+ severity: 'error'
100
+ })
101
+ }
102
+ }
@@ -0,0 +1,81 @@
1
+ import PropTypes from 'prop-types'
2
+ import React, { useState, useRef } from 'react'
3
+
4
+ import EditMenu from './EditMenu'
5
+ import StatusWrapper from './StatusWrapper'
6
+ import Badge from '../Badge'
7
+ import Button from '../Buttons'
8
+ import Icon from '../Icon'
9
+ import PenIcon from '../Icons/Pen'
10
+
11
+ const EditBadge = ({
12
+ src,
13
+ onUpload,
14
+ onDelete,
15
+ anchorOrigin,
16
+ children,
17
+ ...props
18
+ }) => {
19
+ const [showMenu, setShowMenu] = useState(false)
20
+ const [status, setStatus] = useState('PRESENT') // PRESENT || ABSENT || LOADING
21
+ const [timestamp, setTimestamp] = useState(Date.now())
22
+
23
+ const menuAnchorRef = useRef(null)
24
+
25
+ return (
26
+ <Badge
27
+ {...props}
28
+ anchorOrigin={anchorOrigin}
29
+ badgeContent={
30
+ <>
31
+ <Button
32
+ ref={menuAnchorRef}
33
+ component="div"
34
+ className="u-miw-auto u-w-2-half u-h-2-half u-bdrs-circle"
35
+ classes={{ label: 'u-flex u-w-auto' }}
36
+ style={{
37
+ outline: '4px solid var(--paperBackgroundColor)'
38
+ }}
39
+ label={<Icon icon={PenIcon} />}
40
+ size="small"
41
+ onClick={() => setShowMenu(v => !v)}
42
+ />
43
+ <EditMenu
44
+ anchorRef={menuAnchorRef.current}
45
+ status={status}
46
+ showMenu={showMenu}
47
+ setShowMenu={setShowMenu}
48
+ setStatus={setStatus}
49
+ setTimestamp={setTimestamp}
50
+ onUpload={onUpload}
51
+ onDelete={onDelete}
52
+ />
53
+ </>
54
+ }
55
+ >
56
+ <StatusWrapper
57
+ src={src(timestamp)}
58
+ status={status}
59
+ setStatus={setStatus}
60
+ timestamp={timestamp}
61
+ >
62
+ {children}
63
+ </StatusWrapper>
64
+ </Badge>
65
+ )
66
+ }
67
+
68
+ EditBadge.defaultProps = {
69
+ anchorOrigin: {
70
+ vertical: 'bottom',
71
+ horizontal: 'right'
72
+ }
73
+ }
74
+
75
+ EditBadge.propTypes = {
76
+ src: PropTypes.func.isRequired,
77
+ onUpload: PropTypes.func.isRequired,
78
+ onDelete: PropTypes.func.isRequired
79
+ }
80
+
81
+ export default EditBadge
@@ -0,0 +1,18 @@
1
+ {
2
+ "EditBadge": {
3
+ "menu": {
4
+ "update": "Update",
5
+ "delete": "Delete"
6
+ },
7
+ "upload": {
8
+ "file-size": "The file size limit is 5MB.",
9
+ "file-type": "The file type is not supported. Please try again.",
10
+ "success": "Avatar updated successfully",
11
+ "error": "The avatar upload has failed. Please try again."
12
+ },
13
+ "delete": {
14
+ "success": "Avatar deleted successfully",
15
+ "error": "The avatar deletion has failed. Please try again."
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "EditBadge": {
3
+ "menu": {
4
+ "update": "Mettre à jour",
5
+ "delete": "Supprimer"
6
+ },
7
+ "upload": {
8
+ "file-size": "La taille du fichier est limitée à 5Mo.",
9
+ "file-type": "Le type de fichier n'est pas supporté. Merci de réessayer.",
10
+ "success": "Avatar mis à jour avec succès",
11
+ "error": "La mise à jour de l'avatar a échoué. Merci de réessayer."
12
+ },
13
+ "delete": {
14
+ "success": "Avatar supprimé avec succès",
15
+ "error": "La suppression de l'avatar a échoué. Merci de réessayer."
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,11 @@
1
+ import en from './en.json'
2
+ import fr from './fr.json'
3
+ import ru from './ru.json'
4
+ import vi from './vi.json'
5
+
6
+ export const locales = {
7
+ en,
8
+ fr,
9
+ ru,
10
+ vi
11
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "EditBadge": {
3
+ "menu": {
4
+ "update": "Обновить",
5
+ "delete": "Удалить"
6
+ },
7
+ "upload": {
8
+ "file-size": "Максимальный размер файла — 5 МБ.",
9
+ "file-type": "Тип файла не поддерживается. Пожалуйста, попробуйте снова.",
10
+ "success": "Аватар успешно обновлён",
11
+ "error": "Не удалось загрузить аватар. Пожалуйста, попробуйте снова."
12
+ },
13
+ "delete": {
14
+ "success": "Аватар успешно удалён",
15
+ "error": "Не удалось удалить аватар. Пожалуйста, попробуйте снова."
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "EditBadge": {
3
+ "menu": {
4
+ "update": "Cập nhật",
5
+ "delete": "Xóa"
6
+ },
7
+ "upload": {
8
+ "file-size": "Giới hạn kích thước tệp là 5MB.",
9
+ "file-type": "Loại tệp không được hỗ trợ. Vui lòng thử lại.",
10
+ "success": "Cập nhật ảnh đại diện thành công",
11
+ "error": "Tải ảnh đại diện thất bại. Vui lòng thử lại."
12
+ },
13
+ "delete": {
14
+ "success": "Xóa ảnh đại diện thành công",
15
+ "error": "Xóa ảnh đại diện thất bại. Vui lòng thử lại."
16
+ }
17
+ }
18
+ }
@@ -1,4 +1,4 @@
1
- import { Fragment, Children } from 'react'
1
+ import { Fragment, Children, isValidElement, cloneElement } from 'react'
2
2
 
3
3
  /**
4
4
  * Get the name of the node
@@ -33,3 +33,16 @@ export const getLastChild = props => {
33
33
  ? getChildren(lastChild.props)[0]
34
34
  : lastChild
35
35
  }
36
+
37
+ /**
38
+ * Clone a React child and add props on it
39
+ * @param {React.ReactElement} children
40
+ * @param {Function} propsCallback - get child props as arg, return new props as object
41
+ * @returns
42
+ */
43
+ export const AddPropsToChildren = (children, propsCallback) =>
44
+ Children.map(children, child =>
45
+ isValidElement(child)
46
+ ? cloneElement(child, { ...propsCallback(child.props) })
47
+ : null
48
+ )
@@ -0,0 +1,11 @@
1
+ export default EditMenu;
2
+ declare function EditMenu({ anchorRef, status, showMenu, setShowMenu, setStatus, setTimestamp, onUpload, onDelete }: {
3
+ anchorRef: any;
4
+ status: any;
5
+ showMenu: any;
6
+ setShowMenu: any;
7
+ setStatus: any;
8
+ setTimestamp: any;
9
+ onUpload: any;
10
+ onDelete: any;
11
+ }): JSX.Element;
@@ -0,0 +1,93 @@
1
+ import React, { useRef } from 'react';
2
+ import { handleDelete, handleUpload } from "cozy-ui/transpiled/react/EditBadge/helpers";
3
+ import { locales } from "cozy-ui/transpiled/react/EditBadge/locales";
4
+ import Icon from "cozy-ui/transpiled/react/Icon";
5
+ import CameraIcon from "cozy-ui/transpiled/react/Icons/Camera";
6
+ import TrashIcon from "cozy-ui/transpiled/react/Icons/Trash";
7
+ import ListItemIcon from "cozy-ui/transpiled/react/ListItemIcon";
8
+ import ListItemText from "cozy-ui/transpiled/react/ListItemText";
9
+ import Menu from "cozy-ui/transpiled/react/Menu";
10
+ import MenuItem from "cozy-ui/transpiled/react/MenuItem";
11
+ import { useAlert } from "cozy-ui/transpiled/react/providers/Alert";
12
+ import { useI18n, useExtendI18n } from "cozy-ui/transpiled/react/providers/I18n";
13
+
14
+ var EditMenu = function EditMenu(_ref) {
15
+ var anchorRef = _ref.anchorRef,
16
+ status = _ref.status,
17
+ showMenu = _ref.showMenu,
18
+ setShowMenu = _ref.setShowMenu,
19
+ setStatus = _ref.setStatus,
20
+ setTimestamp = _ref.setTimestamp,
21
+ onUpload = _ref.onUpload,
22
+ onDelete = _ref.onDelete;
23
+ useExtendI18n(locales);
24
+
25
+ var _useI18n = useI18n(),
26
+ t = _useI18n.t;
27
+
28
+ var _useAlert = useAlert(),
29
+ showAlert = _useAlert.showAlert;
30
+
31
+ var fileInputRef = useRef(null);
32
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("input", {
33
+ className: "u-dn",
34
+ type: "file",
35
+ ref: fileInputRef,
36
+ accept: "image/*",
37
+ onChange: function onChange(event) {
38
+ return handleUpload({
39
+ event: event,
40
+ t: t,
41
+ fileInputRef: fileInputRef,
42
+ status: status,
43
+ onUpload: onUpload,
44
+ setStatus: setStatus,
45
+ setTimestamp: setTimestamp,
46
+ setShowMenu: setShowMenu,
47
+ showAlert: showAlert
48
+ });
49
+ }
50
+ }), showMenu && /*#__PURE__*/React.createElement(Menu, {
51
+ open: true,
52
+ anchorEl: anchorRef,
53
+ getContentAnchorEl: null,
54
+ anchorOrigin: {
55
+ vertical: 'bottom',
56
+ horizontal: 'left'
57
+ },
58
+ transformOrigin: {
59
+ vertical: 'top',
60
+ horizontal: 'left'
61
+ },
62
+ onClose: function onClose() {
63
+ return setShowMenu(false);
64
+ }
65
+ }, /*#__PURE__*/React.createElement(MenuItem, {
66
+ onClick: function onClick() {
67
+ setShowMenu(false);
68
+ fileInputRef.current.click(); // triggers onChange of the input
69
+ }
70
+ }, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(Icon, {
71
+ icon: CameraIcon
72
+ })), /*#__PURE__*/React.createElement(ListItemText, {
73
+ primary: t('EditBadge.menu.update')
74
+ })), /*#__PURE__*/React.createElement(MenuItem, {
75
+ onClick: function onClick() {
76
+ return handleDelete({
77
+ t: t,
78
+ status: status,
79
+ onDelete: onDelete,
80
+ setShowMenu: setShowMenu,
81
+ setStatus: setStatus,
82
+ setTimestamp: setTimestamp,
83
+ showAlert: showAlert
84
+ });
85
+ }
86
+ }, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(Icon, {
87
+ icon: TrashIcon
88
+ })), /*#__PURE__*/React.createElement(ListItemText, {
89
+ primary: t('EditBadge.menu.delete')
90
+ }))));
91
+ };
92
+
93
+ export default EditMenu;
@@ -0,0 +1,9 @@
1
+ export default StatusWrapper;
2
+ declare function StatusWrapper({ src, status, setStatus, timestamp, children }: {
3
+ src: any;
4
+ status: any;
5
+ setStatus: any;
6
+ timestamp: any;
7
+ children: any;
8
+ }): JSX.Element | (React.ReactElement<any, string | React.JSXElementConstructor<any>> | null)[];
9
+ import React from "react";
@@ -0,0 +1,44 @@
1
+ import cx from 'classnames';
2
+ import React from 'react';
3
+ import Spinner from "cozy-ui/transpiled/react/Spinner";
4
+ import { AddPropsToChildren } from "cozy-ui/transpiled/react/utils/react";
5
+
6
+ var StatusWrapper = function StatusWrapper(_ref) {
7
+ var src = _ref.src,
8
+ status = _ref.status,
9
+ setStatus = _ref.setStatus,
10
+ timestamp = _ref.timestamp,
11
+ children = _ref.children;
12
+
13
+ if (status === 'LOADING') {
14
+ return /*#__PURE__*/React.createElement(React.Fragment, null, AddPropsToChildren(children, function (childProps) {
15
+ return {
16
+ className: cx(childProps.className, 'u-o-50')
17
+ };
18
+ }), /*#__PURE__*/React.createElement(Spinner, {
19
+ className: "u-m-0",
20
+ middle: true,
21
+ size: "large"
22
+ }));
23
+ }
24
+
25
+ if (status === 'PRESENT') {
26
+ return AddPropsToChildren(children, function () {
27
+ return {
28
+ key: timestamp,
29
+ src: src,
30
+ onError: function onError() {
31
+ return setStatus('ABSENT');
32
+ }
33
+ };
34
+ });
35
+ }
36
+
37
+ return AddPropsToChildren(children, function () {
38
+ return {
39
+ key: timestamp
40
+ };
41
+ });
42
+ };
43
+
44
+ export default StatusWrapper;
@@ -0,0 +1,20 @@
1
+ export function handleUpload({ event, t, fileInputRef, status, onUpload, setStatus, setTimestamp, setShowMenu, showAlert }: {
2
+ event: any;
3
+ t: any;
4
+ fileInputRef: any;
5
+ status: any;
6
+ onUpload: any;
7
+ setStatus: any;
8
+ setTimestamp: any;
9
+ setShowMenu: any;
10
+ showAlert: any;
11
+ }): Promise<void>;
12
+ export function handleDelete({ t, status, onDelete, setShowMenu, setStatus, setTimestamp, showAlert }: {
13
+ t: any;
14
+ status: any;
15
+ onDelete: any;
16
+ setShowMenu: any;
17
+ setStatus: any;
18
+ setTimestamp: any;
19
+ showAlert: any;
20
+ }): Promise<void>;
@@ -0,0 +1,153 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
3
+ var MAX_FILE_SIZE = 5 * 1024 * 1024;
4
+ var ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
5
+ export var handleUpload = /*#__PURE__*/function () {
6
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref) {
7
+ var event, t, fileInputRef, status, onUpload, setStatus, setTimestamp, setShowMenu, showAlert, file, controller, timeoutId, previouStatus, newTimestamp;
8
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
9
+ while (1) {
10
+ switch (_context.prev = _context.next) {
11
+ case 0:
12
+ event = _ref.event, t = _ref.t, fileInputRef = _ref.fileInputRef, status = _ref.status, onUpload = _ref.onUpload, setStatus = _ref.setStatus, setTimestamp = _ref.setTimestamp, setShowMenu = _ref.setShowMenu, showAlert = _ref.showAlert;
13
+ file = event.target.files[0];
14
+
15
+ if (file) {
16
+ _context.next = 4;
17
+ break;
18
+ }
19
+
20
+ return _context.abrupt("return");
21
+
22
+ case 4:
23
+ if (!(file.size > MAX_FILE_SIZE)) {
24
+ _context.next = 7;
25
+ break;
26
+ }
27
+
28
+ showAlert({
29
+ message: t('EditBadge.upload.file-size'),
30
+ severity: 'error'
31
+ });
32
+ return _context.abrupt("return");
33
+
34
+ case 7:
35
+ if (ALLOWED_TYPES.includes(file.type)) {
36
+ _context.next = 10;
37
+ break;
38
+ }
39
+
40
+ showAlert({
41
+ message: t('EditBadge.upload.file-type'),
42
+ severity: 'error'
43
+ });
44
+ return _context.abrupt("return");
45
+
46
+ case 10:
47
+ controller = new AbortController();
48
+ timeoutId = setTimeout(function () {
49
+ return controller.abort();
50
+ }, 30000);
51
+ previouStatus = status;
52
+ setStatus('LOADING');
53
+ _context.prev = 14;
54
+ _context.next = 17;
55
+ return onUpload(file);
56
+
57
+ case 17:
58
+ clearTimeout(timeoutId);
59
+ newTimestamp = Date.now();
60
+ setStatus('PRESENT');
61
+ setTimestamp(newTimestamp);
62
+ showAlert({
63
+ message: t('EditBadge.upload.success'),
64
+ severity: 'success'
65
+ });
66
+ _context.next = 29;
67
+ break;
68
+
69
+ case 24:
70
+ _context.prev = 24;
71
+ _context.t0 = _context["catch"](14);
72
+ clearTimeout(timeoutId);
73
+ setStatus(previouStatus);
74
+ showAlert({
75
+ message: t('EditBadge.upload.error'),
76
+ severity: 'error'
77
+ });
78
+
79
+ case 29:
80
+ _context.prev = 29;
81
+ setShowMenu(false);
82
+
83
+ if (fileInputRef.current) {
84
+ fileInputRef.current.value = '';
85
+ }
86
+
87
+ return _context.finish(29);
88
+
89
+ case 33:
90
+ case "end":
91
+ return _context.stop();
92
+ }
93
+ }
94
+ }, _callee, null, [[14, 24, 29, 33]]);
95
+ }));
96
+
97
+ return function handleUpload(_x) {
98
+ return _ref2.apply(this, arguments);
99
+ };
100
+ }();
101
+ export var handleDelete = /*#__PURE__*/function () {
102
+ var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref3) {
103
+ var t, status, onDelete, setShowMenu, setStatus, setTimestamp, showAlert, controller, timeoutId, previousStatus, checkTimestamp;
104
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
105
+ while (1) {
106
+ switch (_context2.prev = _context2.next) {
107
+ case 0:
108
+ t = _ref3.t, status = _ref3.status, onDelete = _ref3.onDelete, setShowMenu = _ref3.setShowMenu, setStatus = _ref3.setStatus, setTimestamp = _ref3.setTimestamp, showAlert = _ref3.showAlert;
109
+ setShowMenu(false);
110
+ controller = new AbortController();
111
+ timeoutId = setTimeout(function () {
112
+ return controller.abort();
113
+ }, 30000);
114
+ previousStatus = status;
115
+ setStatus('LOADING');
116
+ _context2.prev = 6;
117
+ _context2.next = 9;
118
+ return onDelete();
119
+
120
+ case 9:
121
+ clearTimeout(timeoutId);
122
+ checkTimestamp = Date.now();
123
+ setStatus('ABSENT');
124
+ setTimestamp(checkTimestamp);
125
+ showAlert({
126
+ message: t('EditBadge.delete.success'),
127
+ severity: 'success'
128
+ });
129
+ _context2.next = 21;
130
+ break;
131
+
132
+ case 16:
133
+ _context2.prev = 16;
134
+ _context2.t0 = _context2["catch"](6);
135
+ clearTimeout(timeoutId);
136
+ setStatus(previousStatus);
137
+ showAlert({
138
+ message: t('EditBadge.delete.error'),
139
+ severity: 'error'
140
+ });
141
+
142
+ case 21:
143
+ case "end":
144
+ return _context2.stop();
145
+ }
146
+ }
147
+ }, _callee2, null, [[6, 16]]);
148
+ }));
149
+
150
+ return function handleDelete(_x2) {
151
+ return _ref4.apply(this, arguments);
152
+ };
153
+ }();
@@ -0,0 +1,23 @@
1
+ export default EditBadge;
2
+ declare function EditBadge({ src, onUpload, onDelete, anchorOrigin, children, ...props }: {
3
+ [x: string]: any;
4
+ src: any;
5
+ onUpload: any;
6
+ onDelete: any;
7
+ anchorOrigin: any;
8
+ children: any;
9
+ }): JSX.Element;
10
+ declare namespace EditBadge {
11
+ namespace defaultProps {
12
+ namespace anchorOrigin {
13
+ const vertical: string;
14
+ const horizontal: string;
15
+ }
16
+ }
17
+ namespace propTypes {
18
+ const src: PropTypes.Validator<(...args: any[]) => any>;
19
+ const onUpload: PropTypes.Validator<(...args: any[]) => any>;
20
+ const onDelete: PropTypes.Validator<(...args: any[]) => any>;
21
+ }
22
+ }
23
+ import PropTypes from "prop-types";
@@ -0,0 +1,89 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
4
+ var _excluded = ["src", "onUpload", "onDelete", "anchorOrigin", "children"];
5
+ import PropTypes from 'prop-types';
6
+ import React, { useState, useRef } from 'react';
7
+ import EditMenu from "cozy-ui/transpiled/react/EditBadge/EditMenu";
8
+ import StatusWrapper from "cozy-ui/transpiled/react/EditBadge/StatusWrapper";
9
+ import Badge from "cozy-ui/transpiled/react/Badge";
10
+ import Button from "cozy-ui/transpiled/react/Buttons";
11
+ import Icon from "cozy-ui/transpiled/react/Icon";
12
+ import PenIcon from "cozy-ui/transpiled/react/Icons/Pen";
13
+
14
+ var EditBadge = function EditBadge(_ref) {
15
+ var src = _ref.src,
16
+ onUpload = _ref.onUpload,
17
+ onDelete = _ref.onDelete,
18
+ anchorOrigin = _ref.anchorOrigin,
19
+ children = _ref.children,
20
+ props = _objectWithoutProperties(_ref, _excluded);
21
+
22
+ var _useState = useState(false),
23
+ _useState2 = _slicedToArray(_useState, 2),
24
+ showMenu = _useState2[0],
25
+ setShowMenu = _useState2[1];
26
+
27
+ var _useState3 = useState('PRESENT'),
28
+ _useState4 = _slicedToArray(_useState3, 2),
29
+ status = _useState4[0],
30
+ setStatus = _useState4[1]; // PRESENT || ABSENT || LOADING
31
+
32
+
33
+ var _useState5 = useState(Date.now()),
34
+ _useState6 = _slicedToArray(_useState5, 2),
35
+ timestamp = _useState6[0],
36
+ setTimestamp = _useState6[1];
37
+
38
+ var menuAnchorRef = useRef(null);
39
+ return /*#__PURE__*/React.createElement(Badge, _extends({}, props, {
40
+ anchorOrigin: anchorOrigin,
41
+ badgeContent: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
42
+ ref: menuAnchorRef,
43
+ component: "div",
44
+ className: "u-miw-auto u-w-2-half u-h-2-half u-bdrs-circle",
45
+ classes: {
46
+ label: 'u-flex u-w-auto'
47
+ },
48
+ style: {
49
+ outline: '4px solid var(--paperBackgroundColor)'
50
+ },
51
+ label: /*#__PURE__*/React.createElement(Icon, {
52
+ icon: PenIcon
53
+ }),
54
+ size: "small",
55
+ onClick: function onClick() {
56
+ return setShowMenu(function (v) {
57
+ return !v;
58
+ });
59
+ }
60
+ }), /*#__PURE__*/React.createElement(EditMenu, {
61
+ anchorRef: menuAnchorRef.current,
62
+ status: status,
63
+ showMenu: showMenu,
64
+ setShowMenu: setShowMenu,
65
+ setStatus: setStatus,
66
+ setTimestamp: setTimestamp,
67
+ onUpload: onUpload,
68
+ onDelete: onDelete
69
+ }))
70
+ }), /*#__PURE__*/React.createElement(StatusWrapper, {
71
+ src: src(timestamp),
72
+ status: status,
73
+ setStatus: setStatus,
74
+ timestamp: timestamp
75
+ }, children));
76
+ };
77
+
78
+ EditBadge.defaultProps = {
79
+ anchorOrigin: {
80
+ vertical: 'bottom',
81
+ horizontal: 'right'
82
+ }
83
+ };
84
+ EditBadge.propTypes = {
85
+ src: PropTypes.func.isRequired,
86
+ onUpload: PropTypes.func.isRequired,
87
+ onDelete: PropTypes.func.isRequired
88
+ };
89
+ export default EditBadge;
@@ -0,0 +1,10 @@
1
+ export namespace locales {
2
+ export { en };
3
+ export { fr };
4
+ export { ru };
5
+ export { vi };
6
+ }
7
+ import en from "./en.json";
8
+ import fr from "./fr.json";
9
+ import ru from "./ru.json";
10
+ import vi from "./vi.json";
@@ -0,0 +1,78 @@
1
+ var en = {
2
+ EditBadge: {
3
+ menu: {
4
+ update: "Update",
5
+ "delete": "Delete"
6
+ },
7
+ upload: {
8
+ "file-size": "The file size limit is 5MB.",
9
+ "file-type": "The file type is not supported. Please try again.",
10
+ success: "Avatar updated successfully",
11
+ error: "The avatar upload has failed. Please try again."
12
+ },
13
+ "delete": {
14
+ success: "Avatar deleted successfully",
15
+ error: "The avatar deletion has failed. Please try again."
16
+ }
17
+ }
18
+ };
19
+ var fr = {
20
+ EditBadge: {
21
+ menu: {
22
+ update: "Mettre \xE0 jour",
23
+ "delete": "Supprimer"
24
+ },
25
+ upload: {
26
+ "file-size": "La taille du fichier est limit\xE9e \xE0 5Mo.",
27
+ "file-type": "Le type de fichier n'est pas support\xE9. Merci de r\xE9essayer.",
28
+ success: "Avatar mis \xE0 jour avec succ\xE8s",
29
+ error: "La mise \xE0 jour de l'avatar a \xE9chou\xE9. Merci de r\xE9essayer."
30
+ },
31
+ "delete": {
32
+ success: "Avatar supprim\xE9 avec succ\xE8s",
33
+ error: "La suppression de l'avatar a \xE9chou\xE9. Merci de r\xE9essayer."
34
+ }
35
+ }
36
+ };
37
+ var ru = {
38
+ EditBadge: {
39
+ menu: {
40
+ update: "\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C",
41
+ "delete": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C"
42
+ },
43
+ upload: {
44
+ "file-size": "\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 \u0444\u0430\u0439\u043B\u0430 \u2014 5 \u041C\u0411.",
45
+ "file-type": "\u0422\u0438\u043F \u0444\u0430\u0439\u043B\u0430 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430.",
46
+ success: "\u0410\u0432\u0430\u0442\u0430\u0440 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D",
47
+ error: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0430\u0432\u0430\u0442\u0430\u0440. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430."
48
+ },
49
+ "delete": {
50
+ success: "\u0410\u0432\u0430\u0442\u0430\u0440 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0451\u043D",
51
+ error: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0430\u0432\u0430\u0442\u0430\u0440. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430."
52
+ }
53
+ }
54
+ };
55
+ var vi = {
56
+ EditBadge: {
57
+ menu: {
58
+ update: "C\u1EADp nh\u1EADt",
59
+ "delete": "X\xF3a"
60
+ },
61
+ upload: {
62
+ "file-size": "Gi\u1EDBi h\u1EA1n k\xEDch th\u01B0\u1EDBc t\u1EC7p l\xE0 5MB.",
63
+ "file-type": "Lo\u1EA1i t\u1EC7p kh\xF4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3. Vui l\xF2ng th\u1EED l\u1EA1i.",
64
+ success: "C\u1EADp nh\u1EADt \u1EA3nh \u0111\u1EA1i di\u1EC7n th\xE0nh c\xF4ng",
65
+ error: "T\u1EA3i \u1EA3nh \u0111\u1EA1i di\u1EC7n th\u1EA5t b\u1EA1i. Vui l\xF2ng th\u1EED l\u1EA1i."
66
+ },
67
+ "delete": {
68
+ success: "X\xF3a \u1EA3nh \u0111\u1EA1i di\u1EC7n th\xE0nh c\xF4ng",
69
+ error: "X\xF3a \u1EA3nh \u0111\u1EA1i di\u1EC7n th\u1EA5t b\u1EA1i. Vui l\xF2ng th\u1EED l\u1EA1i."
70
+ }
71
+ }
72
+ };
73
+ export var locales = {
74
+ en: en,
75
+ fr: fr,
76
+ ru: ru,
77
+ vi: vi
78
+ };
@@ -2,3 +2,4 @@ export function getComponentName(node: any): any;
2
2
  export function getChildren(props: any): any[] | null;
3
3
  export function getChildrenCount(props: any): number | null;
4
4
  export function getLastChild(props: any): any;
5
+ export function AddPropsToChildren(children: React.ReactElement, propsCallback: Function): (import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>> | null)[];
@@ -1,4 +1,10 @@
1
- import { Fragment, Children } from 'react';
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
+
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
6
+
7
+ import { Fragment, Children, isValidElement, cloneElement } from 'react';
2
8
  /**
3
9
  * Get the name of the node
4
10
  * @param {React.ElementType || string} node
@@ -26,4 +32,16 @@ export var getLastChild = function getLastChild(props) {
26
32
  if (!children) return null;
27
33
  var lastChild = children[children.length - 1];
28
34
  return lastChild.type === Fragment ? getChildren(lastChild.props)[0] : lastChild;
35
+ };
36
+ /**
37
+ * Clone a React child and add props on it
38
+ * @param {React.ReactElement} children
39
+ * @param {Function} propsCallback - get child props as arg, return new props as object
40
+ * @returns
41
+ */
42
+
43
+ export var AddPropsToChildren = function AddPropsToChildren(children, propsCallback) {
44
+ return Children.map(children, function (child) {
45
+ return /*#__PURE__*/isValidElement(child) ? /*#__PURE__*/cloneElement(child, _objectSpread({}, propsCallback(child.props))) : null;
46
+ });
29
47
  };