@plesk/ui-library 3.27.2 → 3.28.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/cjs/components/Dialog/Dialog.js +11 -2
- package/cjs/components/Form/Form.js +4 -2
- package/cjs/components/FormFieldPassword/FormFieldPassword.js +25 -239
- package/cjs/components/FormFieldPassword/PasswordMeter.js +81 -0
- package/cjs/components/FormFieldPassword/estimatePassword.js +212 -0
- package/cjs/components/FormFieldPassword/generatePassword.js +21 -0
- package/cjs/components/FormFieldPassword/index.js +5 -5
- package/cjs/components/Icon/constants.js +2 -2
- package/cjs/components/Icon/images/symbols.svg +9 -1
- package/cjs/components/ProgressDialog/ProgressDialog.js +2 -1
- package/cjs/components/Skeleton/Skeleton.js +49 -0
- package/cjs/components/Skeleton/Skeleton.stories.js +26 -0
- package/cjs/components/Skeleton/SkeletonTabs.js +41 -0
- package/cjs/components/Skeleton/SkeletonTabs.stories.js +17 -0
- package/cjs/components/Skeleton/SkeletonText.js +45 -0
- package/cjs/components/Skeleton/SkeletonText.stories.js +35 -0
- package/cjs/components/Skeleton/index.js +31 -0
- package/cjs/components/index.js +22 -1
- package/cjs/components/utils.js +6 -2
- package/cjs/index.js +1 -1
- package/dist/images/symbols.svg +9 -1
- package/dist/plesk-ui-library-rtl.css +1 -1
- package/dist/plesk-ui-library-rtl.css.map +1 -1
- package/dist/plesk-ui-library.css +1 -1
- package/dist/plesk-ui-library.css.map +1 -1
- package/dist/plesk-ui-library.js +607 -339
- package/dist/plesk-ui-library.js.map +1 -1
- package/dist/plesk-ui-library.min.js +5 -5
- package/dist/plesk-ui-library.min.js.map +1 -1
- package/esm/components/Dialog/Dialog.js +11 -2
- package/esm/components/Form/Form.js +4 -2
- package/esm/components/FormFieldPassword/FormFieldPassword.js +23 -232
- package/esm/components/FormFieldPassword/PasswordMeter.js +61 -0
- package/esm/components/FormFieldPassword/estimatePassword.js +196 -0
- package/esm/components/FormFieldPassword/generatePassword.js +14 -0
- package/esm/components/FormFieldPassword/index.js +3 -2
- package/esm/components/Icon/constants.js +2 -2
- package/esm/components/Icon/images/symbols.svg +9 -1
- package/esm/components/ProgressDialog/ProgressDialog.js +2 -1
- package/esm/components/Skeleton/Skeleton.js +34 -0
- package/esm/components/Skeleton/Skeleton.stories.js +10 -0
- package/esm/components/Skeleton/SkeletonTabs.js +26 -0
- package/esm/components/Skeleton/SkeletonTabs.stories.js +4 -0
- package/esm/components/Skeleton/SkeletonText.js +30 -0
- package/esm/components/Skeleton/SkeletonText.stories.js +16 -0
- package/esm/components/Skeleton/index.js +4 -0
- package/esm/components/index.js +3 -1
- package/esm/components/utils.js +2 -1
- package/esm/index.js +1 -1
- package/package.json +3 -3
- package/styleguide/build/bundle.24d5b0eb.js +2 -0
- package/styleguide/build/{bundle.1c9c8500.js.LICENSE.txt → bundle.24d5b0eb.js.LICENSE.txt} +0 -0
- package/styleguide/images/symbols.svg +9 -1
- package/styleguide/index.html +2 -2
- package/types/src/components/FormFieldPassword/FormFieldPassword.d.ts +91 -0
- package/types/src/components/FormFieldPassword/PasswordMeter.d.ts +9 -0
- package/types/src/components/FormFieldPassword/estimatePassword.d.ts +13 -0
- package/types/src/components/FormFieldPassword/index.d.ts +2 -0
- package/types/src/components/Icon/constants.d.ts +1 -1
- package/types/src/components/Skeleton/Skeleton.d.ts +49 -0
- package/types/src/components/Skeleton/Skeleton.stories.d.ts +12 -0
- package/types/src/components/Skeleton/SkeletonTabs.d.ts +23 -0
- package/types/src/components/Skeleton/SkeletonTabs.stories.d.ts +6 -0
- package/types/src/components/Skeleton/SkeletonText.d.ts +34 -0
- package/types/src/components/Skeleton/SkeletonText.stories.d.ts +38 -0
- package/types/src/components/Skeleton/index.d.ts +3 -0
- package/types/src/components/index.d.ts +2 -0
- package/types/src/components/utils.d.ts +1 -0
- package/cjs/components/FormFieldPassword/passwordScore.js +0 -132
- package/esm/components/FormFieldPassword/passwordScore.js +0 -123
- package/styleguide/build/bundle.1c9c8500.js +0 -2
|
@@ -40,6 +40,7 @@ const Dialog = ({
|
|
|
40
40
|
closable,
|
|
41
41
|
onClose,
|
|
42
42
|
closingConfirmation,
|
|
43
|
+
canClose,
|
|
43
44
|
...props
|
|
44
45
|
}) => {
|
|
45
46
|
const [isVisible, setIsVisible] = useState(isOpen);
|
|
@@ -150,8 +151,8 @@ const Dialog = ({
|
|
|
150
151
|
className: classNames(baseClassName, className),
|
|
151
152
|
isOpen: isVisible,
|
|
152
153
|
onClose: onCloseWithConfirmation,
|
|
153
|
-
canCloseOnBackdropClick: closable,
|
|
154
|
-
canCloseOnEscapePress: closable,
|
|
154
|
+
canCloseOnBackdropClick: canClose && closable,
|
|
155
|
+
canCloseOnEscapePress: canClose && closable,
|
|
155
156
|
size: size
|
|
156
157
|
}, props), (title || subtitle || actions) && /*#__PURE__*/React.createElement("header", {
|
|
157
158
|
className: `${baseClassName}__header`
|
|
@@ -174,6 +175,7 @@ const Dialog = ({
|
|
|
174
175
|
className: `${baseClassName}__header-actions`
|
|
175
176
|
}, actions, closable && /*#__PURE__*/React.createElement(Button, {
|
|
176
177
|
className: `${baseClassName}__header-close`,
|
|
178
|
+
disabled: !canClose,
|
|
177
179
|
ghost: true,
|
|
178
180
|
size: "lg",
|
|
179
181
|
icon: "cross-mark",
|
|
@@ -279,6 +281,12 @@ Dialog.propTypes = {
|
|
|
279
281
|
*/
|
|
280
282
|
closable: PropTypes.bool,
|
|
281
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Disable close dialog button
|
|
286
|
+
* @since 4.0.0
|
|
287
|
+
*/
|
|
288
|
+
canClose: PropTypes.bool,
|
|
289
|
+
|
|
282
290
|
/**
|
|
283
291
|
* On close event handler. Called immediately after dialog closed by "cancel" button or "Esc" key.
|
|
284
292
|
* @since 0.0.68
|
|
@@ -322,6 +330,7 @@ Dialog.defaultProps = {
|
|
|
322
330
|
form: undefined,
|
|
323
331
|
size: 'md',
|
|
324
332
|
closable: true,
|
|
333
|
+
canClose: true,
|
|
325
334
|
onClose: undefined,
|
|
326
335
|
closingConfirmation: undefined,
|
|
327
336
|
children: undefined,
|
|
@@ -248,9 +248,11 @@ class Form extends Component {
|
|
|
248
248
|
let field;
|
|
249
249
|
let fieldErrors;
|
|
250
250
|
Object.keys(this.fields).every(name => {
|
|
251
|
-
|
|
251
|
+
const foundError = getIn(errors, name);
|
|
252
|
+
|
|
253
|
+
if (foundError && typeof foundError === 'object' && Object.keys(foundError).length > 0) {
|
|
252
254
|
field = this.fields[name];
|
|
253
|
-
fieldErrors =
|
|
255
|
+
fieldErrors = foundError;
|
|
254
256
|
return false;
|
|
255
257
|
}
|
|
256
258
|
|
|
@@ -1,49 +1,30 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
-
// Copyright 1999-
|
|
3
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
4
4
|
import React, { Component, Fragment, createRef } from 'react';
|
|
5
|
-
import PropTypes from 'prop-types';
|
|
6
5
|
import classNames from 'classnames';
|
|
7
6
|
import { CLS_PREFIX } from '../../constants';
|
|
8
7
|
import Button from '../Button';
|
|
9
8
|
import FormField from '../FormField';
|
|
10
9
|
import Input from '../Input';
|
|
11
|
-
import Popover from '../Popover';
|
|
12
10
|
import Translate from '../Translate';
|
|
13
|
-
import
|
|
11
|
+
import PasswordMeter from './PasswordMeter';
|
|
12
|
+
import generatePassword from './generatePassword';
|
|
14
13
|
import locale from './locale/en-US';
|
|
15
|
-
|
|
16
|
-
upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
17
|
-
lower: 'abcdefghijklmnopqrstuvwxyz',
|
|
18
|
-
number: '0123456789',
|
|
19
|
-
special: '!@#$%^&*?_~'
|
|
20
|
-
};
|
|
21
|
-
export const generatePassword = () => {
|
|
22
|
-
const password = ['upper', 'lower', 'lower', 'lower', 'number', 'number', 'special', 'number', 'upper', 'upper', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower'];
|
|
23
|
-
return password.sort((a, b) => Math.floor(b.length * Math.random()) - Math.floor(a.length * Math.random())).map(symbolClass => symbolClasses[symbolClass][Math.floor(symbolClasses[symbolClass].length * Math.random())]).join('');
|
|
24
|
-
};
|
|
14
|
+
|
|
25
15
|
/**
|
|
26
16
|
* `FormFieldPassword` component provides secure way to enter a password.
|
|
27
17
|
* @since 0.0.58
|
|
28
18
|
*/
|
|
29
|
-
|
|
30
19
|
class FormFieldPassword extends Component {
|
|
31
20
|
constructor(...args) {
|
|
32
21
|
super(...args);
|
|
33
22
|
|
|
34
23
|
_defineProperty(this, "state", {
|
|
35
24
|
visible: false,
|
|
36
|
-
passwordMeterVisible: false
|
|
37
|
-
scoreResult: {
|
|
38
|
-
password: null,
|
|
39
|
-
intent: null,
|
|
40
|
-
strength: null,
|
|
41
|
-
unusedRules: []
|
|
42
|
-
}
|
|
25
|
+
passwordMeterVisible: false
|
|
43
26
|
});
|
|
44
27
|
|
|
45
|
-
_defineProperty(this, "passwordOnScoring", null);
|
|
46
|
-
|
|
47
28
|
_defineProperty(this, "targetRef", /*#__PURE__*/createRef());
|
|
48
29
|
|
|
49
30
|
_defineProperty(this, "handleToggleClick", () => {
|
|
@@ -63,134 +44,6 @@ class FormFieldPassword extends Component {
|
|
|
63
44
|
_defineProperty(this, "handleBlur", this.handleClosePasswordMeter);
|
|
64
45
|
}
|
|
65
46
|
|
|
66
|
-
async passwordScore(value) {
|
|
67
|
-
if (!value) {
|
|
68
|
-
return {
|
|
69
|
-
password: null,
|
|
70
|
-
intent: null,
|
|
71
|
-
strength: null,
|
|
72
|
-
unusedRules: []
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const {
|
|
77
|
-
passwordScoreRules
|
|
78
|
-
} = this.props;
|
|
79
|
-
const {
|
|
80
|
-
password,
|
|
81
|
-
score,
|
|
82
|
-
unusedRules
|
|
83
|
-
} = await passwordScore(value, passwordScoreRules);
|
|
84
|
-
let intent = 'success';
|
|
85
|
-
let strength = /*#__PURE__*/React.createElement(Translate, {
|
|
86
|
-
content: "FormFieldPassword.strengthVeryStrong",
|
|
87
|
-
fallback: locale.strengthVeryStrong
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
if (score < 16) {
|
|
91
|
-
intent = 'danger';
|
|
92
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
93
|
-
content: "FormFieldPassword.strengthVeryWeak",
|
|
94
|
-
fallback: locale.strengthVeryWeak
|
|
95
|
-
});
|
|
96
|
-
} else if (score < 25) {
|
|
97
|
-
intent = 'danger';
|
|
98
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
99
|
-
content: "FormFieldPassword.strengthWeak",
|
|
100
|
-
fallback: locale.strengthWeak
|
|
101
|
-
});
|
|
102
|
-
} else if (score < 35) {
|
|
103
|
-
intent = 'warning';
|
|
104
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
105
|
-
content: "FormFieldPassword.strengthMedium",
|
|
106
|
-
fallback: locale.strengthMedium
|
|
107
|
-
});
|
|
108
|
-
} else if (score < 45) {
|
|
109
|
-
intent = 'success';
|
|
110
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
111
|
-
content: "FormFieldPassword.strengthStrong",
|
|
112
|
-
fallback: locale.strengthStrong
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
password,
|
|
118
|
-
intent,
|
|
119
|
-
strength,
|
|
120
|
-
unusedRules
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
renderPasswordMeter(value, target) {
|
|
125
|
-
const {
|
|
126
|
-
passwordMeterVisible
|
|
127
|
-
} = this.state;
|
|
128
|
-
const {
|
|
129
|
-
passwordMeterProps
|
|
130
|
-
} = this.props;
|
|
131
|
-
const {
|
|
132
|
-
password,
|
|
133
|
-
intent,
|
|
134
|
-
strength,
|
|
135
|
-
unusedRules
|
|
136
|
-
} = this.state.scoreResult;
|
|
137
|
-
|
|
138
|
-
if (!!value && value !== password && value !== this.passwordOnScoring) {
|
|
139
|
-
this.passwordOnScoring = value;
|
|
140
|
-
this.passwordScore(value).then(scoreResult => {
|
|
141
|
-
if (this.passwordOnScoring === scoreResult.password) {
|
|
142
|
-
this.passwordOnScoring = null;
|
|
143
|
-
this.setState({
|
|
144
|
-
scoreResult
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return /*#__PURE__*/React.createElement(Popover, _extends({
|
|
151
|
-
visible: passwordMeterVisible && !!value,
|
|
152
|
-
target: target,
|
|
153
|
-
targetRef: this.targetRef,
|
|
154
|
-
placement: "bottom-right",
|
|
155
|
-
intent: intent,
|
|
156
|
-
canCloseOnOutsideClick: false,
|
|
157
|
-
canCloseOnEscapePress: false,
|
|
158
|
-
onClose: this.handleClosePasswordMeter
|
|
159
|
-
}, passwordMeterProps), /*#__PURE__*/React.createElement(Translate, {
|
|
160
|
-
content: "FormFieldPassword.passwordStrength",
|
|
161
|
-
fallback: locale.passwordStrength,
|
|
162
|
-
params: {
|
|
163
|
-
strength: /*#__PURE__*/React.createElement("b", null, strength)
|
|
164
|
-
}
|
|
165
|
-
}), /*#__PURE__*/React.createElement("br", null), unusedRules.length ? /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Translate, {
|
|
166
|
-
content: "FormFieldPassword.improvePassword",
|
|
167
|
-
fallback: locale.improvePassword
|
|
168
|
-
}), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("ul", null, unusedRules.slice(0, 3).map(({
|
|
169
|
-
rule
|
|
170
|
-
}, index) => {
|
|
171
|
-
const {
|
|
172
|
-
name
|
|
173
|
-
} = rule;
|
|
174
|
-
let {
|
|
175
|
-
message
|
|
176
|
-
} = rule;
|
|
177
|
-
|
|
178
|
-
if (name && !message) {
|
|
179
|
-
message = /*#__PURE__*/React.createElement(Translate, {
|
|
180
|
-
content: `FormFieldPassword.${name}`,
|
|
181
|
-
fallback: locale[name]
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return /*#__PURE__*/React.createElement("li", {
|
|
186
|
-
key: name || index.toString()
|
|
187
|
-
}, message);
|
|
188
|
-
}))) : /*#__PURE__*/React.createElement(Translate, {
|
|
189
|
-
content: "FormFieldPassword.yourPasswordIsStrong",
|
|
190
|
-
fallback: locale.yourPasswordIsStrong
|
|
191
|
-
}));
|
|
192
|
-
}
|
|
193
|
-
|
|
194
47
|
renderGenerateButton({
|
|
195
48
|
setValue,
|
|
196
49
|
isDisabled
|
|
@@ -232,12 +85,15 @@ class FormFieldPassword extends Component {
|
|
|
232
85
|
hideGenerateButton,
|
|
233
86
|
hidePasswordMeter,
|
|
234
87
|
passwordMeterProps,
|
|
235
|
-
passwordScoreRules,
|
|
236
88
|
size,
|
|
237
89
|
autoFocus,
|
|
238
90
|
autoComplete,
|
|
239
91
|
...props
|
|
240
92
|
} = this.props;
|
|
93
|
+
const {
|
|
94
|
+
visible,
|
|
95
|
+
passwordMeterVisible
|
|
96
|
+
} = this.state;
|
|
241
97
|
return /*#__PURE__*/React.createElement(FormField, _extends({
|
|
242
98
|
className: classNames(baseClassName, className)
|
|
243
99
|
}, props), ({
|
|
@@ -247,18 +103,18 @@ class FormFieldPassword extends Component {
|
|
|
247
103
|
setValue,
|
|
248
104
|
isDisabled
|
|
249
105
|
}) => {
|
|
106
|
+
const value = getValue('');
|
|
250
107
|
const input = /*#__PURE__*/React.createElement(Input, {
|
|
251
108
|
id: getId(),
|
|
252
109
|
name: getName(),
|
|
253
|
-
type:
|
|
254
|
-
value:
|
|
110
|
+
type: visible ? 'text' : 'password',
|
|
111
|
+
value: value,
|
|
255
112
|
onChange: e => {
|
|
256
113
|
setValue(e.target.value);
|
|
257
114
|
this.setState({
|
|
258
115
|
passwordMeterVisible: true
|
|
259
116
|
});
|
|
260
117
|
},
|
|
261
|
-
onFocus: this.handleFocus,
|
|
262
118
|
onBlur: this.handleBlur,
|
|
263
119
|
autoFocus: autoFocus,
|
|
264
120
|
autoComplete: autoComplete,
|
|
@@ -267,8 +123,8 @@ class FormFieldPassword extends Component {
|
|
|
267
123
|
suffix: hideShowButton ? null : /*#__PURE__*/React.createElement(Button, {
|
|
268
124
|
className: `${baseClassName}__button--show`,
|
|
269
125
|
onClick: this.handleToggleClick,
|
|
270
|
-
icon:
|
|
271
|
-
tooltip:
|
|
126
|
+
icon: visible ? 'visible' : 'invisible',
|
|
127
|
+
tooltip: visible ? /*#__PURE__*/React.createElement(Translate, {
|
|
272
128
|
content: "FormFieldPassword.hidePassword",
|
|
273
129
|
fallback: locale.hidePassword
|
|
274
130
|
}) : /*#__PURE__*/React.createElement(Translate, {
|
|
@@ -287,7 +143,12 @@ class FormFieldPassword extends Component {
|
|
|
287
143
|
className: classNames(`${baseClassName}__control`, `${baseClassName}__control--${size}`)
|
|
288
144
|
}, /*#__PURE__*/React.createElement("div", {
|
|
289
145
|
className: classNames(`${baseClassName}__field`, `${baseClassName}__field--${size}`)
|
|
290
|
-
}, hidePasswordMeter ? input :
|
|
146
|
+
}, hidePasswordMeter ? input : /*#__PURE__*/React.createElement(PasswordMeter, _extends({
|
|
147
|
+
value: value,
|
|
148
|
+
targetRef: this.targetRef,
|
|
149
|
+
visible: passwordMeterVisible && value !== '',
|
|
150
|
+
onClose: this.handleClosePasswordMeter
|
|
151
|
+
}, passwordMeterProps), input)), hideGenerateButton ? null : this.renderGenerateButton({
|
|
291
152
|
setValue,
|
|
292
153
|
isDisabled
|
|
293
154
|
}));
|
|
@@ -296,87 +157,17 @@ class FormFieldPassword extends Component {
|
|
|
296
157
|
|
|
297
158
|
}
|
|
298
159
|
|
|
299
|
-
FormFieldPassword
|
|
300
|
-
/**
|
|
301
|
-
* Is show button hidden?
|
|
302
|
-
* @since 0.0.59
|
|
303
|
-
*/
|
|
304
|
-
hideShowButton: PropTypes.bool,
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Is generate button hidden?
|
|
308
|
-
* @since 0.0.59
|
|
309
|
-
*/
|
|
310
|
-
hideGenerateButton: PropTypes.bool,
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Is password meter hidden?
|
|
314
|
-
* @since 0.0.59
|
|
315
|
-
*/
|
|
316
|
-
hidePasswordMeter: PropTypes.bool,
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Additional props for password meter. . See [Popover](#!/Popover) for more information.
|
|
320
|
-
* @since 1.5.6
|
|
321
|
-
*/
|
|
322
|
-
passwordMeterProps: PropTypes.object,
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* A set of custom password score rules.
|
|
326
|
-
* @since 3.21.0
|
|
327
|
-
*/
|
|
328
|
-
passwordScoreRules: PropTypes.arrayOf(PropTypes.shape({
|
|
329
|
-
name: PropTypes.string,
|
|
330
|
-
message: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
|
|
331
|
-
score: PropTypes.func.isRequired
|
|
332
|
-
})),
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Size of the control
|
|
336
|
-
* @since 1.5.6
|
|
337
|
-
*/
|
|
338
|
-
size: PropTypes.oneOf(['md', 'lg', 'xl', 'fill']),
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* The browser will automatically focus on the component upon rendering the screen
|
|
342
|
-
* @since 1.9.0
|
|
343
|
-
*/
|
|
344
|
-
autoFocus: PropTypes.bool,
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Prevent password autocompletion.
|
|
348
|
-
* @since 2.5.1
|
|
349
|
-
*/
|
|
350
|
-
autoComplete: PropTypes.oneOf(['new-password']),
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* A render function for customizing the password generation button.
|
|
354
|
-
* @since 3.13.0
|
|
355
|
-
*/
|
|
356
|
-
generateButton: PropTypes.func,
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* @ignore
|
|
360
|
-
*/
|
|
361
|
-
className: PropTypes.string,
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* @ignore
|
|
365
|
-
*/
|
|
366
|
-
baseClassName: PropTypes.string
|
|
367
|
-
};
|
|
368
|
-
FormFieldPassword.defaultProps = {
|
|
160
|
+
_defineProperty(FormFieldPassword, "defaultProps", {
|
|
369
161
|
hideShowButton: false,
|
|
370
162
|
generateButton: undefined,
|
|
371
163
|
hideGenerateButton: false,
|
|
372
164
|
hidePasswordMeter: false,
|
|
373
165
|
passwordMeterProps: {},
|
|
374
|
-
passwordScoreRules: undefined,
|
|
375
166
|
size: 'md',
|
|
376
167
|
autoFocus: undefined,
|
|
377
168
|
autoComplete: undefined,
|
|
378
169
|
className: undefined,
|
|
379
170
|
baseClassName: `${CLS_PREFIX}form-field-password`
|
|
380
|
-
};
|
|
381
|
-
|
|
171
|
+
});
|
|
172
|
+
|
|
382
173
|
export default FormFieldPassword;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
3
|
+
import React, { Fragment, useState, useEffect } from 'react';
|
|
4
|
+
import Popover from '../Popover';
|
|
5
|
+
import Translate from '../Translate';
|
|
6
|
+
import estimatePassword, { DEFAULT_RULES } from './estimatePassword';
|
|
7
|
+
import locale from './locale/en-US';
|
|
8
|
+
const strengthIntents = {
|
|
9
|
+
VeryWeak: 'danger',
|
|
10
|
+
Weak: 'danger',
|
|
11
|
+
Medium: 'warning',
|
|
12
|
+
Strong: 'success',
|
|
13
|
+
VeryStrong: 'success'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const PasswordMeter = ({
|
|
17
|
+
value,
|
|
18
|
+
visible,
|
|
19
|
+
onEstimate,
|
|
20
|
+
children,
|
|
21
|
+
...props
|
|
22
|
+
}) => {
|
|
23
|
+
const [result, setResult] = useState(null);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!visible) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Promise.resolve(onEstimate ? onEstimate(value, estimatePassword, DEFAULT_RULES) : estimatePassword(value)).then(result => {
|
|
30
|
+
setResult(result);
|
|
31
|
+
});
|
|
32
|
+
}, [visible, value, onEstimate]);
|
|
33
|
+
return /*#__PURE__*/React.createElement(Popover, _extends({
|
|
34
|
+
visible: visible && result !== null,
|
|
35
|
+
target: children,
|
|
36
|
+
placement: "bottom-right",
|
|
37
|
+
intent: result ? strengthIntents[result.strength] : undefined,
|
|
38
|
+
canCloseOnOutsideClick: false,
|
|
39
|
+
canCloseOnEscapePress: false
|
|
40
|
+
}, props), result !== null && result !== void 0 && result.strength ? /*#__PURE__*/React.createElement(Translate, {
|
|
41
|
+
component: "div",
|
|
42
|
+
content: "FormFieldPassword.passwordStrength",
|
|
43
|
+
fallback: locale.passwordStrength,
|
|
44
|
+
params: {
|
|
45
|
+
strength: /*#__PURE__*/React.createElement("b", null, /*#__PURE__*/React.createElement(Translate, {
|
|
46
|
+
content: `FormFieldPassword.strength${result === null || result === void 0 ? void 0 : result.strength}`,
|
|
47
|
+
fallback: locale[`strength${result === null || result === void 0 ? void 0 : result.strength}`]
|
|
48
|
+
}))
|
|
49
|
+
}
|
|
50
|
+
}) : null, result !== null && result !== void 0 && result.suggestions.length ? /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Translate, {
|
|
51
|
+
content: "FormFieldPassword.improvePassword",
|
|
52
|
+
fallback: locale.improvePassword
|
|
53
|
+
}), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("ul", null, result.suggestions.slice(0, 3).map((suggestion, index) => /*#__PURE__*/React.createElement("li", {
|
|
54
|
+
key: index.toString()
|
|
55
|
+
}, suggestion)))) : /*#__PURE__*/React.createElement(Translate, {
|
|
56
|
+
content: "FormFieldPassword.yourPasswordIsStrong",
|
|
57
|
+
fallback: locale.yourPasswordIsStrong
|
|
58
|
+
}));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default PasswordMeter;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import Translate from '../Translate';
|
|
4
|
+
import locale from './locale/en-US';
|
|
5
|
+
const EXCLUSIONS = {
|
|
6
|
+
numbers1: 'numbers3',
|
|
7
|
+
specialChar1: 'specialChar2',
|
|
8
|
+
lettersLowerCase: 'comboUpperAndLower',
|
|
9
|
+
lettersUpperCase: 'comboUpperAndLower'
|
|
10
|
+
};
|
|
11
|
+
export const DEFAULT_RULES = [{
|
|
12
|
+
name: 'passwordTooShort',
|
|
13
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
14
|
+
content: `FormFieldPassword.passwordTooShort`,
|
|
15
|
+
fallback: locale.passwordTooShort
|
|
16
|
+
}),
|
|
17
|
+
|
|
18
|
+
score(passwd) {
|
|
19
|
+
return passwd.length < 5 ? -1 : 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
}, {
|
|
23
|
+
name: 'passwordLength',
|
|
24
|
+
|
|
25
|
+
score(passwd) {
|
|
26
|
+
if (passwd.length < 5) {
|
|
27
|
+
return 3;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (passwd.length > 4 && passwd.length < 8) {
|
|
31
|
+
return 6;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (passwd.length > 7 && passwd.length < 16) {
|
|
35
|
+
return 12;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return 18;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}, {
|
|
42
|
+
name: 'lettersLowerCase',
|
|
43
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
44
|
+
content: `FormFieldPassword.lettersLowerCase`,
|
|
45
|
+
fallback: locale.lettersLowerCase
|
|
46
|
+
}),
|
|
47
|
+
|
|
48
|
+
score(passwd) {
|
|
49
|
+
// [verified] at least one lower case letter
|
|
50
|
+
return passwd.match(/[a-z]/) ? 1 : -1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
}, {
|
|
54
|
+
name: 'lettersUpperCase',
|
|
55
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
56
|
+
content: `FormFieldPassword.lettersUpperCase`,
|
|
57
|
+
fallback: locale.lettersUpperCase
|
|
58
|
+
}),
|
|
59
|
+
|
|
60
|
+
score(passwd) {
|
|
61
|
+
// [verified] at least one upper case letter
|
|
62
|
+
return passwd.match(/[A-Z]/) ? 5 : -1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}, {
|
|
66
|
+
name: 'numbers1',
|
|
67
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
68
|
+
content: `FormFieldPassword.numbers1`,
|
|
69
|
+
fallback: locale.numbers1
|
|
70
|
+
}),
|
|
71
|
+
|
|
72
|
+
score(passwd) {
|
|
73
|
+
// [verified] at least one number
|
|
74
|
+
return passwd.match(/\d+/) ? 5 : -1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}, {
|
|
78
|
+
name: 'numbers3',
|
|
79
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
80
|
+
content: `FormFieldPassword.numbers3`,
|
|
81
|
+
fallback: locale.numbers3
|
|
82
|
+
}),
|
|
83
|
+
|
|
84
|
+
score(passwd) {
|
|
85
|
+
// [verified] at least three numbers
|
|
86
|
+
return passwd.match(/(.*[0-9].*[0-9].*[0-9])/) ? 5 : -1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}, {
|
|
90
|
+
name: 'specialChar1',
|
|
91
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
92
|
+
content: `FormFieldPassword.specialChar1`,
|
|
93
|
+
fallback: locale.specialChar1
|
|
94
|
+
}),
|
|
95
|
+
|
|
96
|
+
score(passwd) {
|
|
97
|
+
// [verified] at least one special character
|
|
98
|
+
return passwd.match(/[!@#$%^&*?_~]/) ? 5 : -1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
}, {
|
|
102
|
+
name: 'specialChar2',
|
|
103
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
104
|
+
content: `FormFieldPassword.specialChar2`,
|
|
105
|
+
fallback: locale.specialChar2
|
|
106
|
+
}),
|
|
107
|
+
|
|
108
|
+
score(passwd) {
|
|
109
|
+
// [verified] at least two special characters
|
|
110
|
+
return passwd.match(/(.*[!@#$%^&*?_~].*[!@#$%^&*?_~])/) ? 5 : -1;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}, {
|
|
114
|
+
name: 'comboUpperAndLower',
|
|
115
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
116
|
+
content: `FormFieldPassword.comboUpperAndLower`,
|
|
117
|
+
fallback: locale.comboUpperAndLower
|
|
118
|
+
}),
|
|
119
|
+
|
|
120
|
+
score(passwd) {
|
|
121
|
+
// [verified] both upper and lower case
|
|
122
|
+
return passwd.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ? 2 : -1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
}, {
|
|
126
|
+
name: 'comboLettersAndNumbers',
|
|
127
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
128
|
+
content: `FormFieldPassword.comboLettersAndNumbers`,
|
|
129
|
+
fallback: locale.comboLettersAndNumbers
|
|
130
|
+
}),
|
|
131
|
+
|
|
132
|
+
score(passwd) {
|
|
133
|
+
// [verified] both letters and numbers
|
|
134
|
+
return passwd.match(/([a-zA-Z])/) && passwd.match(/([0-9])/) ? 2 : -1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
}, {
|
|
138
|
+
name: 'comboLettersNumbersSpecial',
|
|
139
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
140
|
+
content: `FormFieldPassword.comboLettersNumbersSpecial`,
|
|
141
|
+
fallback: locale.comboLettersNumbersSpecial
|
|
142
|
+
}),
|
|
143
|
+
|
|
144
|
+
score(passwd) {
|
|
145
|
+
// [verified] letters, numbers, and special characters
|
|
146
|
+
return passwd.match(/([a-zA-Z0-9].*[!@#$%^&*?_~])|([!@#$%^&*?_~].*[a-zA-Z0-9])/) ? 2 : -1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
}];
|
|
150
|
+
export default ((password, rules = DEFAULT_RULES) => {
|
|
151
|
+
let passwordScore = 0;
|
|
152
|
+
const suggestions = [];
|
|
153
|
+
const skippedRules = new Set();
|
|
154
|
+
rules.forEach(rule => {
|
|
155
|
+
const ruleScore = rule.score(password);
|
|
156
|
+
|
|
157
|
+
if (ruleScore >= 0) {
|
|
158
|
+
passwordScore += ruleScore;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
skippedRules.add(EXCLUSIONS[rule.name]);
|
|
163
|
+
|
|
164
|
+
if (!skippedRules.has(rule.name) && rule.suggestion) {
|
|
165
|
+
suggestions.push(rule.suggestion);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
let strength;
|
|
169
|
+
|
|
170
|
+
switch (true) {
|
|
171
|
+
case passwordScore < 16:
|
|
172
|
+
strength = 'VeryWeak';
|
|
173
|
+
break;
|
|
174
|
+
|
|
175
|
+
case passwordScore < 25:
|
|
176
|
+
strength = 'Weak';
|
|
177
|
+
break;
|
|
178
|
+
|
|
179
|
+
case passwordScore < 35:
|
|
180
|
+
strength = 'Medium';
|
|
181
|
+
break;
|
|
182
|
+
|
|
183
|
+
case passwordScore < 45:
|
|
184
|
+
strength = 'Strong';
|
|
185
|
+
break;
|
|
186
|
+
|
|
187
|
+
default:
|
|
188
|
+
strength = 'VeryStrong';
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
strength,
|
|
194
|
+
suggestions
|
|
195
|
+
};
|
|
196
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
2
|
+
const symbolClasses = {
|
|
3
|
+
upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
4
|
+
lower: 'abcdefghijklmnopqrstuvwxyz',
|
|
5
|
+
number: '0123456789',
|
|
6
|
+
special: '!@#$%^&*?_~'
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const generatePassword = () => {
|
|
10
|
+
const password = ['upper', 'upper', 'upper', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower', 'number', 'number', 'number', 'special', 'special'];
|
|
11
|
+
return password.sort((a, b) => Math.floor(b.length * Math.random()) - Math.floor(a.length * Math.random())).map(symbolClass => symbolClasses[symbolClass][Math.floor(symbolClasses[symbolClass].length * Math.random())]).join('');
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default generatePassword;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
// Copyright 1999-
|
|
2
|
-
export { default
|
|
1
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
2
|
+
export { default } from './FormFieldPassword';
|
|
3
|
+
export { default as generatePassword } from './generatePassword';
|