@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.
Files changed (71) hide show
  1. package/cjs/components/Dialog/Dialog.js +11 -2
  2. package/cjs/components/Form/Form.js +4 -2
  3. package/cjs/components/FormFieldPassword/FormFieldPassword.js +25 -239
  4. package/cjs/components/FormFieldPassword/PasswordMeter.js +81 -0
  5. package/cjs/components/FormFieldPassword/estimatePassword.js +212 -0
  6. package/cjs/components/FormFieldPassword/generatePassword.js +21 -0
  7. package/cjs/components/FormFieldPassword/index.js +5 -5
  8. package/cjs/components/Icon/constants.js +2 -2
  9. package/cjs/components/Icon/images/symbols.svg +9 -1
  10. package/cjs/components/ProgressDialog/ProgressDialog.js +2 -1
  11. package/cjs/components/Skeleton/Skeleton.js +49 -0
  12. package/cjs/components/Skeleton/Skeleton.stories.js +26 -0
  13. package/cjs/components/Skeleton/SkeletonTabs.js +41 -0
  14. package/cjs/components/Skeleton/SkeletonTabs.stories.js +17 -0
  15. package/cjs/components/Skeleton/SkeletonText.js +45 -0
  16. package/cjs/components/Skeleton/SkeletonText.stories.js +35 -0
  17. package/cjs/components/Skeleton/index.js +31 -0
  18. package/cjs/components/index.js +22 -1
  19. package/cjs/components/utils.js +6 -2
  20. package/cjs/index.js +1 -1
  21. package/dist/images/symbols.svg +9 -1
  22. package/dist/plesk-ui-library-rtl.css +1 -1
  23. package/dist/plesk-ui-library-rtl.css.map +1 -1
  24. package/dist/plesk-ui-library.css +1 -1
  25. package/dist/plesk-ui-library.css.map +1 -1
  26. package/dist/plesk-ui-library.js +607 -339
  27. package/dist/plesk-ui-library.js.map +1 -1
  28. package/dist/plesk-ui-library.min.js +5 -5
  29. package/dist/plesk-ui-library.min.js.map +1 -1
  30. package/esm/components/Dialog/Dialog.js +11 -2
  31. package/esm/components/Form/Form.js +4 -2
  32. package/esm/components/FormFieldPassword/FormFieldPassword.js +23 -232
  33. package/esm/components/FormFieldPassword/PasswordMeter.js +61 -0
  34. package/esm/components/FormFieldPassword/estimatePassword.js +196 -0
  35. package/esm/components/FormFieldPassword/generatePassword.js +14 -0
  36. package/esm/components/FormFieldPassword/index.js +3 -2
  37. package/esm/components/Icon/constants.js +2 -2
  38. package/esm/components/Icon/images/symbols.svg +9 -1
  39. package/esm/components/ProgressDialog/ProgressDialog.js +2 -1
  40. package/esm/components/Skeleton/Skeleton.js +34 -0
  41. package/esm/components/Skeleton/Skeleton.stories.js +10 -0
  42. package/esm/components/Skeleton/SkeletonTabs.js +26 -0
  43. package/esm/components/Skeleton/SkeletonTabs.stories.js +4 -0
  44. package/esm/components/Skeleton/SkeletonText.js +30 -0
  45. package/esm/components/Skeleton/SkeletonText.stories.js +16 -0
  46. package/esm/components/Skeleton/index.js +4 -0
  47. package/esm/components/index.js +3 -1
  48. package/esm/components/utils.js +2 -1
  49. package/esm/index.js +1 -1
  50. package/package.json +3 -3
  51. package/styleguide/build/bundle.24d5b0eb.js +2 -0
  52. package/styleguide/build/{bundle.1c9c8500.js.LICENSE.txt → bundle.24d5b0eb.js.LICENSE.txt} +0 -0
  53. package/styleguide/images/symbols.svg +9 -1
  54. package/styleguide/index.html +2 -2
  55. package/types/src/components/FormFieldPassword/FormFieldPassword.d.ts +91 -0
  56. package/types/src/components/FormFieldPassword/PasswordMeter.d.ts +9 -0
  57. package/types/src/components/FormFieldPassword/estimatePassword.d.ts +13 -0
  58. package/types/src/components/FormFieldPassword/index.d.ts +2 -0
  59. package/types/src/components/Icon/constants.d.ts +1 -1
  60. package/types/src/components/Skeleton/Skeleton.d.ts +49 -0
  61. package/types/src/components/Skeleton/Skeleton.stories.d.ts +12 -0
  62. package/types/src/components/Skeleton/SkeletonTabs.d.ts +23 -0
  63. package/types/src/components/Skeleton/SkeletonTabs.stories.d.ts +6 -0
  64. package/types/src/components/Skeleton/SkeletonText.d.ts +34 -0
  65. package/types/src/components/Skeleton/SkeletonText.stories.d.ts +38 -0
  66. package/types/src/components/Skeleton/index.d.ts +3 -0
  67. package/types/src/components/index.d.ts +2 -0
  68. package/types/src/components/utils.d.ts +1 -0
  69. package/cjs/components/FormFieldPassword/passwordScore.js +0 -132
  70. package/esm/components/FormFieldPassword/passwordScore.js +0 -123
  71. 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
- if (errors && errors[name] && typeof errors[name] === 'object' && Object.keys(errors[name]).length > 0) {
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 = errors[name];
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-2021. Plesk International GmbH. All rights reserved.
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 passwordScore, { PASSWORD_SCORE_RULES } from './passwordScore';
11
+ import PasswordMeter from './PasswordMeter';
12
+ import generatePassword from './generatePassword';
14
13
  import locale from './locale/en-US';
15
- const symbolClasses = {
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: this.state.visible ? 'text' : 'password',
254
- value: getValue(''),
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: this.state.visible ? 'visible' : 'invisible',
271
- tooltip: this.state.visible ? /*#__PURE__*/React.createElement(Translate, {
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 : this.renderPasswordMeter(getValue(), input)), hideGenerateButton ? null : this.renderGenerateButton({
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.propTypes = {
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
- FormFieldPassword.PASSWORD_SCORE_RULES = PASSWORD_SCORE_RULES;
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-2017. Plesk International GmbH. All rights reserved.
2
- export { default, generatePassword } from './FormFieldPassword';
1
+ // Copyright 1999-2022. Plesk International GmbH. All rights reserved.
2
+ export { default } from './FormFieldPassword';
3
+ export { default as generatePassword } from './generatePassword';