@peassoft/mnr-web-topline 4.0.1 → 4.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/dist/en/modules/ui-lang/index.d.ts +4 -8
- package/dist/en/modules/ui-lang/index.js +6 -18
- package/dist/en/parts/profile/ui/root/has-changes.js +1 -1
- package/dist/en/parts/profile/ui/root/index.js +3 -3
- package/dist/en/parts/signup/actions/perform-signup/index.d.ts +2 -1
- package/dist/en/parts/signup/ui/signup/index.js +17 -3
- package/dist/ru/modules/ui-lang/index.d.ts +4 -8
- package/dist/ru/modules/ui-lang/index.js +6 -18
- package/dist/ru/parts/profile/ui/root/has-changes.js +1 -1
- package/dist/ru/parts/profile/ui/root/index.js +3 -3
- package/dist/ru/parts/signup/actions/perform-signup/index.d.ts +2 -1
- package/dist/ru/parts/signup/ui/signup/index.js +17 -3
- package/package.json +3 -2
- package/dist/en/parts/profile/ui/root/get-initial-ui-lang.d.ts +0 -2
- package/dist/en/parts/profile/ui/root/get-initial-ui-lang.js +0 -4
- package/dist/ru/parts/profile/ui/root/get-initial-ui-lang.d.ts +0 -2
- package/dist/ru/parts/profile/ui/root/get-initial-ui-lang.js +0 -4
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
6
|
-
export declare function getSupportedUiLangs(): NonEmptyArray<UiLangDescriptor>;
|
|
7
|
-
export declare function getDefaultUiLangForUser(): UiLangDescriptor;
|
|
8
|
-
export {};
|
|
1
|
+
import { type SupportedLanguage } from '@peassoft/mnr-langs';
|
|
2
|
+
import type { ToplineUser } from '../../types/data.js';
|
|
3
|
+
export declare function getPageLang(): SupportedLanguage;
|
|
4
|
+
export declare function getInitialUiLang(user: ToplineUser): string;
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
code: 'ru',
|
|
6
|
-
name: 'Русский'
|
|
7
|
-
}];
|
|
8
|
-
export function getSupportedUiLangs() {
|
|
9
|
-
return window.structuredClone(supportedUiLangs);
|
|
1
|
+
import { defaultLanguage, validateLanguage } from '@peassoft/mnr-langs';
|
|
2
|
+
export function getPageLang() {
|
|
3
|
+
const currPageLang = document.querySelector('html')?.lang;
|
|
4
|
+
return validateLanguage(currPageLang) || defaultLanguage;
|
|
10
5
|
}
|
|
11
|
-
export function
|
|
12
|
-
|
|
13
|
-
const normalizedLangCode = lang.slice(0, 2).toLowerCase();
|
|
14
|
-
const matchedDescriptor = supportedUiLangs.find(x => x.code === normalizedLangCode);
|
|
15
|
-
if (matchedDescriptor) {
|
|
16
|
-
return window.structuredClone(matchedDescriptor);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return supportedUiLangs[0];
|
|
6
|
+
export function getInitialUiLang(user) {
|
|
7
|
+
return user.uiLang ?? getPageLang();
|
|
20
8
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import getInitialUserName from './get-initial-user-name.js';
|
|
2
|
-
import getInitialUiLang from '
|
|
2
|
+
import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
|
|
3
3
|
export default function hasChanges(user, currData) {
|
|
4
4
|
if (getInitialUserName(user) !== currData.userName) {
|
|
5
5
|
return true;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useMemo, useCallback } from 'react';
|
|
3
|
+
import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
|
|
3
4
|
import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
|
|
4
5
|
import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
|
|
5
6
|
import { TextButton } from '@peassoft/mnr-web-ui-kit/text-button/index.js';
|
|
6
7
|
import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
|
|
7
8
|
import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
|
|
8
9
|
import { createUserDataChangeBeacon } from '../../../../modules/user-data-change-beacon/index.js';
|
|
9
|
-
import { getSupportedUiLangs } from '../../../../modules/ui-lang/index.js';
|
|
10
10
|
import { updateUser } from '../../../../modules/local-db/index.js';
|
|
11
11
|
import { innerToplineService, ToplineEventName } from '../../../../modules/topline-service/index.js';
|
|
12
12
|
import saveUserData from '../../actions/save-user-data/index.js';
|
|
13
|
+
import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
|
|
13
14
|
import getInitialUserName from './get-initial-user-name.js';
|
|
14
|
-
import getInitialUiLang from './get-initial-ui-lang.js';
|
|
15
15
|
import hasChanges from './has-changes.js';
|
|
16
16
|
export default function Root(props) {
|
|
17
17
|
const {
|
|
@@ -23,7 +23,7 @@ export default function Root(props) {
|
|
|
23
23
|
const [uiLang, setUiLang] = useState(getInitialUiLang(user));
|
|
24
24
|
const [isInProgress, setIsInProgress] = useState(false);
|
|
25
25
|
const [hasSavingError, setHasSavingError] = useState(false);
|
|
26
|
-
const uiLangOptions = useMemo(() =>
|
|
26
|
+
const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
|
|
27
27
|
id: langDescriptor.code,
|
|
28
28
|
value: langDescriptor.name
|
|
29
29
|
})), []);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { SupportedLanguage } from '@peassoft/mnr-langs';
|
|
1
2
|
import type { ToplineUser } from '../../../../types/data.js';
|
|
2
3
|
export type UserData = {
|
|
3
4
|
email: string;
|
|
4
5
|
password: string;
|
|
5
6
|
userName?: string;
|
|
6
|
-
uiLang
|
|
7
|
+
uiLang: SupportedLanguage;
|
|
7
8
|
};
|
|
8
9
|
export type ReturnValue = {
|
|
9
10
|
user: ToplineUser | null;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useContext, useState, useCallback, useEffect, createRef } from 'react';
|
|
2
|
+
import { useContext, useState, useCallback, useMemo, useEffect, createRef } from 'react';
|
|
3
|
+
import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
|
|
3
4
|
import Modal from '../../../../shared/components/modal/index.js';
|
|
4
5
|
import Alternative from '../../../../shared/components/alternative/index.js';
|
|
5
6
|
import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
|
|
6
7
|
import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
|
|
7
8
|
import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
|
|
9
|
+
import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
|
|
8
10
|
import { ToplineContext } from '../../../shell/index.js';
|
|
9
11
|
import { globalRefs } from '../../../../modules/focus-marshal/index.js';
|
|
10
12
|
import validateEmail from '../../../../modules/validators/email.js';
|
|
11
13
|
import validatePassword from '../../../../modules/validators/password.js';
|
|
14
|
+
import { getPageLang } from '../../../../modules/ui-lang/index.js';
|
|
12
15
|
import performSignup from '../../actions/perform-signup/index.js';
|
|
13
16
|
export default function Signup(props) {
|
|
14
17
|
const {
|
|
@@ -20,6 +23,7 @@ export default function Signup(props) {
|
|
|
20
23
|
const [email, setEmail] = useState('');
|
|
21
24
|
const [isEmailValid, setIsEmailValid] = useState(true);
|
|
22
25
|
const [userName, setUserName] = useState('');
|
|
26
|
+
const [uiLang, setUiLang] = useState(getPageLang());
|
|
23
27
|
const [password, setPassword] = useState('');
|
|
24
28
|
const [isPasswordValid, setIsPasswordValid] = useState(true);
|
|
25
29
|
const [passwordConfirmation, setPasswordConfirmation] = useState('');
|
|
@@ -29,8 +33,13 @@ export default function Signup(props) {
|
|
|
29
33
|
const {
|
|
30
34
|
handleUserChange
|
|
31
35
|
} = useContext(ToplineContext);
|
|
36
|
+
const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
|
|
37
|
+
id: langDescriptor.code,
|
|
38
|
+
value: langDescriptor.name
|
|
39
|
+
})), []);
|
|
32
40
|
const handleEmailChange = useCallback(newValue => setEmail(newValue.trim()), []);
|
|
33
41
|
const handleUserNameChange = useCallback(newValue => setUserName(newValue), []);
|
|
42
|
+
const handleUiLangChange = useCallback(val => setUiLang(val), []);
|
|
34
43
|
const handlePasswordChange = useCallback(newValue => setPassword(newValue.trim()), []);
|
|
35
44
|
const handlePasswordConfirmationChange = useCallback(newValue => setPasswordConfirmation(newValue.trim()), []);
|
|
36
45
|
const handleEmailBlur = useCallback(() => setIsEmailValid(validateEmail(email)), [email]);
|
|
@@ -58,7 +67,7 @@ export default function Signup(props) {
|
|
|
58
67
|
...(userName ? {
|
|
59
68
|
userName: userName.trim()
|
|
60
69
|
} : {}),
|
|
61
|
-
uiLang
|
|
70
|
+
uiLang
|
|
62
71
|
};
|
|
63
72
|
const {
|
|
64
73
|
user,
|
|
@@ -80,7 +89,7 @@ export default function Signup(props) {
|
|
|
80
89
|
default:
|
|
81
90
|
throw new Error('Unknown error of a login request');
|
|
82
91
|
}
|
|
83
|
-
}, [email, password, passwordConfirmation, userName, onClose, handleUserChange]);
|
|
92
|
+
}, [email, uiLang, password, passwordConfirmation, userName, onClose, handleUserChange]);
|
|
84
93
|
const handleTabOnLastElement = useCallback(() => globalRefs.modalFirstItem.current?.focus(), []);
|
|
85
94
|
const handleShiftTabOnFirstElement = useCallback(() => lastElementRef.current?.focus(), [lastElementRef]);
|
|
86
95
|
useEffect(() => globalRefs.modalFirstItem.current?.focus(), []);
|
|
@@ -107,6 +116,11 @@ export default function Signup(props) {
|
|
|
107
116
|
label: "Your name",
|
|
108
117
|
value: userName,
|
|
109
118
|
onChange: handleUserNameChange
|
|
119
|
+
}), _jsx(Select, {
|
|
120
|
+
label: "Preferred language for user interface",
|
|
121
|
+
items: uiLangOptions,
|
|
122
|
+
selectedItemId: uiLang,
|
|
123
|
+
onChange: handleUiLangChange
|
|
110
124
|
}), _jsx(InputField, {
|
|
111
125
|
type: 'password',
|
|
112
126
|
autocompleteAttribute: 'new-password',
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
6
|
-
export declare function getSupportedUiLangs(): NonEmptyArray<UiLangDescriptor>;
|
|
7
|
-
export declare function getDefaultUiLangForUser(): UiLangDescriptor;
|
|
8
|
-
export {};
|
|
1
|
+
import { type SupportedLanguage } from '@peassoft/mnr-langs';
|
|
2
|
+
import type { ToplineUser } from '../../types/data.js';
|
|
3
|
+
export declare function getPageLang(): SupportedLanguage;
|
|
4
|
+
export declare function getInitialUiLang(user: ToplineUser): string;
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
code: 'ru',
|
|
6
|
-
name: 'Русский'
|
|
7
|
-
}];
|
|
8
|
-
export function getSupportedUiLangs() {
|
|
9
|
-
return window.structuredClone(supportedUiLangs);
|
|
1
|
+
import { defaultLanguage, validateLanguage } from '@peassoft/mnr-langs';
|
|
2
|
+
export function getPageLang() {
|
|
3
|
+
const currPageLang = document.querySelector('html')?.lang;
|
|
4
|
+
return validateLanguage(currPageLang) || defaultLanguage;
|
|
10
5
|
}
|
|
11
|
-
export function
|
|
12
|
-
|
|
13
|
-
const normalizedLangCode = lang.slice(0, 2).toLowerCase();
|
|
14
|
-
const matchedDescriptor = supportedUiLangs.find(x => x.code === normalizedLangCode);
|
|
15
|
-
if (matchedDescriptor) {
|
|
16
|
-
return window.structuredClone(matchedDescriptor);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return supportedUiLangs[0];
|
|
6
|
+
export function getInitialUiLang(user) {
|
|
7
|
+
return user.uiLang ?? getPageLang();
|
|
20
8
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import getInitialUserName from './get-initial-user-name.js';
|
|
2
|
-
import getInitialUiLang from '
|
|
2
|
+
import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
|
|
3
3
|
export default function hasChanges(user, currData) {
|
|
4
4
|
if (getInitialUserName(user) !== currData.userName) {
|
|
5
5
|
return true;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useMemo, useCallback } from 'react';
|
|
3
|
+
import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
|
|
3
4
|
import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
|
|
4
5
|
import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
|
|
5
6
|
import { TextButton } from '@peassoft/mnr-web-ui-kit/text-button/index.js';
|
|
6
7
|
import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
|
|
7
8
|
import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
|
|
8
9
|
import { createUserDataChangeBeacon } from '../../../../modules/user-data-change-beacon/index.js';
|
|
9
|
-
import { getSupportedUiLangs } from '../../../../modules/ui-lang/index.js';
|
|
10
10
|
import { updateUser } from '../../../../modules/local-db/index.js';
|
|
11
11
|
import { innerToplineService, ToplineEventName } from '../../../../modules/topline-service/index.js';
|
|
12
12
|
import saveUserData from '../../actions/save-user-data/index.js';
|
|
13
|
+
import { getInitialUiLang } from '../../../../modules/ui-lang/index.js';
|
|
13
14
|
import getInitialUserName from './get-initial-user-name.js';
|
|
14
|
-
import getInitialUiLang from './get-initial-ui-lang.js';
|
|
15
15
|
import hasChanges from './has-changes.js';
|
|
16
16
|
export default function Root(props) {
|
|
17
17
|
const {
|
|
@@ -23,7 +23,7 @@ export default function Root(props) {
|
|
|
23
23
|
const [uiLang, setUiLang] = useState(getInitialUiLang(user));
|
|
24
24
|
const [isInProgress, setIsInProgress] = useState(false);
|
|
25
25
|
const [hasSavingError, setHasSavingError] = useState(false);
|
|
26
|
-
const uiLangOptions = useMemo(() =>
|
|
26
|
+
const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
|
|
27
27
|
id: langDescriptor.code,
|
|
28
28
|
value: langDescriptor.name
|
|
29
29
|
})), []);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { SupportedLanguage } from '@peassoft/mnr-langs';
|
|
1
2
|
import type { ToplineUser } from '../../../../types/data.js';
|
|
2
3
|
export type UserData = {
|
|
3
4
|
email: string;
|
|
4
5
|
password: string;
|
|
5
6
|
userName?: string;
|
|
6
|
-
uiLang
|
|
7
|
+
uiLang: SupportedLanguage;
|
|
7
8
|
};
|
|
8
9
|
export type ReturnValue = {
|
|
9
10
|
user: ToplineUser | null;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useContext, useState, useCallback, useEffect, createRef } from 'react';
|
|
2
|
+
import { useContext, useState, useCallback, useMemo, useEffect, createRef } from 'react';
|
|
3
|
+
import { supportedLanguagesDescriptors } from '@peassoft/mnr-langs';
|
|
3
4
|
import Modal from '../../../../shared/components/modal/index.js';
|
|
4
5
|
import Alternative from '../../../../shared/components/alternative/index.js';
|
|
5
6
|
import { InputField } from '@peassoft/mnr-web-ui-kit/input-field/index.js';
|
|
6
7
|
import { Button } from '@peassoft/mnr-web-ui-kit/button/index.js';
|
|
7
8
|
import { ErrorMessage } from '@peassoft/mnr-web-ui-kit/error-message/index.js';
|
|
9
|
+
import { Select } from '@peassoft/mnr-web-ui-kit/select/index.js';
|
|
8
10
|
import { ToplineContext } from '../../../shell/index.js';
|
|
9
11
|
import { globalRefs } from '../../../../modules/focus-marshal/index.js';
|
|
10
12
|
import validateEmail from '../../../../modules/validators/email.js';
|
|
11
13
|
import validatePassword from '../../../../modules/validators/password.js';
|
|
14
|
+
import { getPageLang } from '../../../../modules/ui-lang/index.js';
|
|
12
15
|
import performSignup from '../../actions/perform-signup/index.js';
|
|
13
16
|
export default function Signup(props) {
|
|
14
17
|
const {
|
|
@@ -20,6 +23,7 @@ export default function Signup(props) {
|
|
|
20
23
|
const [email, setEmail] = useState('');
|
|
21
24
|
const [isEmailValid, setIsEmailValid] = useState(true);
|
|
22
25
|
const [userName, setUserName] = useState('');
|
|
26
|
+
const [uiLang, setUiLang] = useState(getPageLang());
|
|
23
27
|
const [password, setPassword] = useState('');
|
|
24
28
|
const [isPasswordValid, setIsPasswordValid] = useState(true);
|
|
25
29
|
const [passwordConfirmation, setPasswordConfirmation] = useState('');
|
|
@@ -29,8 +33,13 @@ export default function Signup(props) {
|
|
|
29
33
|
const {
|
|
30
34
|
handleUserChange
|
|
31
35
|
} = useContext(ToplineContext);
|
|
36
|
+
const uiLangOptions = useMemo(() => supportedLanguagesDescriptors().map(langDescriptor => ({
|
|
37
|
+
id: langDescriptor.code,
|
|
38
|
+
value: langDescriptor.name
|
|
39
|
+
})), []);
|
|
32
40
|
const handleEmailChange = useCallback(newValue => setEmail(newValue.trim()), []);
|
|
33
41
|
const handleUserNameChange = useCallback(newValue => setUserName(newValue), []);
|
|
42
|
+
const handleUiLangChange = useCallback(val => setUiLang(val), []);
|
|
34
43
|
const handlePasswordChange = useCallback(newValue => setPassword(newValue.trim()), []);
|
|
35
44
|
const handlePasswordConfirmationChange = useCallback(newValue => setPasswordConfirmation(newValue.trim()), []);
|
|
36
45
|
const handleEmailBlur = useCallback(() => setIsEmailValid(validateEmail(email)), [email]);
|
|
@@ -58,7 +67,7 @@ export default function Signup(props) {
|
|
|
58
67
|
...(userName ? {
|
|
59
68
|
userName: userName.trim()
|
|
60
69
|
} : {}),
|
|
61
|
-
uiLang
|
|
70
|
+
uiLang
|
|
62
71
|
};
|
|
63
72
|
const {
|
|
64
73
|
user,
|
|
@@ -80,7 +89,7 @@ export default function Signup(props) {
|
|
|
80
89
|
default:
|
|
81
90
|
throw new Error('Unknown error of a login request');
|
|
82
91
|
}
|
|
83
|
-
}, [email, password, passwordConfirmation, userName, onClose, handleUserChange]);
|
|
92
|
+
}, [email, uiLang, password, passwordConfirmation, userName, onClose, handleUserChange]);
|
|
84
93
|
const handleTabOnLastElement = useCallback(() => globalRefs.modalFirstItem.current?.focus(), []);
|
|
85
94
|
const handleShiftTabOnFirstElement = useCallback(() => lastElementRef.current?.focus(), [lastElementRef]);
|
|
86
95
|
useEffect(() => globalRefs.modalFirstItem.current?.focus(), []);
|
|
@@ -107,6 +116,11 @@ export default function Signup(props) {
|
|
|
107
116
|
label: "Ваше имя",
|
|
108
117
|
value: userName,
|
|
109
118
|
onChange: handleUserNameChange
|
|
119
|
+
}), _jsx(Select, {
|
|
120
|
+
label: "Предпочитаемый язык для пользовательского интерфейса",
|
|
121
|
+
items: uiLangOptions,
|
|
122
|
+
selectedItemId: uiLang,
|
|
123
|
+
onChange: handleUiLangChange
|
|
110
124
|
}), _jsx(InputField, {
|
|
111
125
|
type: 'password',
|
|
112
126
|
autocompleteAttribute: 'new-password',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peassoft/mnr-web-topline",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Peassoft Topline widget for mem'n'rev web applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@vitejs/plugin-react": "^5.1.4",
|
|
43
43
|
"autoprefixer": "^10.3.4",
|
|
44
44
|
"clean-webpack-plugin": "^4.0.0",
|
|
45
|
-
"copy-webpack-plugin": "^
|
|
45
|
+
"copy-webpack-plugin": "^14.0.0",
|
|
46
46
|
"cpy-cli": "^7.0.0",
|
|
47
47
|
"css-loader": "^7.1.2",
|
|
48
48
|
"eslint": "^9.8.0",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@memnrev/web-error": "^0.4.1",
|
|
70
|
+
"@peassoft/mnr-langs": "^1.2.0",
|
|
70
71
|
"email-validator": "^2.0.4",
|
|
71
72
|
"md5": "^2.3.0",
|
|
72
73
|
"react-error-boundary": "^6.0.0",
|