2025-05-10 02:09:06 +02:00
|
|
|
/*!
|
|
|
|
|
* Copyright (c) 2024 PLANKA Software GmbH
|
|
|
|
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
|
|
|
|
*/
|
|
|
|
|
|
2022-09-03 22:47:06 +05:00
|
|
|
import zxcvbn from 'zxcvbn';
|
|
|
|
|
import React, { useCallback, useMemo } from 'react';
|
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
import { Icon, Input, Progress } from 'semantic-ui-react';
|
2019-11-15 03:45:59 +05:00
|
|
|
import { useToggle } from '../../../hooks';
|
|
|
|
|
|
2022-09-03 22:47:06 +05:00
|
|
|
import styles from './InputPassword.module.css';
|
|
|
|
|
|
|
|
|
|
const STRENGTH_SCORE_COLORS = ['red', 'orange', 'yellow', 'olive', 'green'];
|
|
|
|
|
|
|
|
|
|
const InputPassword = React.forwardRef(
|
2025-09-22 20:35:13 +02:00
|
|
|
({ value, withStrengthBar, minStrengthScore, className, onClear, ...props }, ref) => {
|
2022-09-03 22:47:06 +05:00
|
|
|
const [isVisible, toggleVisible] = useToggle();
|
|
|
|
|
|
|
|
|
|
const strengthScore = useMemo(() => {
|
|
|
|
|
if (!withStrengthBar) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return zxcvbn(value).score;
|
|
|
|
|
}, [value, withStrengthBar]);
|
|
|
|
|
|
|
|
|
|
const handleToggleClick = useCallback(() => {
|
|
|
|
|
toggleVisible();
|
|
|
|
|
}, [toggleVisible]);
|
|
|
|
|
|
|
|
|
|
const inputProps = {
|
|
|
|
|
...props,
|
|
|
|
|
ref,
|
2025-09-22 20:35:13 +02:00
|
|
|
value,
|
2022-09-03 22:47:06 +05:00
|
|
|
type: isVisible ? 'text' : 'password',
|
2025-09-22 20:35:13 +02:00
|
|
|
icon: onClear ? (
|
|
|
|
|
<Icon link name="cancel" onClick={onClear} />
|
|
|
|
|
) : (
|
|
|
|
|
<Icon link name={isVisible ? 'eye' : 'eye slash'} onClick={handleToggleClick} />
|
|
|
|
|
),
|
2022-09-03 22:47:06 +05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!withStrengthBar) {
|
|
|
|
|
return (
|
|
|
|
|
<Input
|
|
|
|
|
{...inputProps} // eslint-disable-line react/jsx-props-no-spreading
|
|
|
|
|
className={className}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={className}>
|
|
|
|
|
<Input
|
|
|
|
|
{...inputProps} // eslint-disable-line react/jsx-props-no-spreading
|
|
|
|
|
error={!!value && strengthScore < minStrengthScore}
|
|
|
|
|
/>
|
|
|
|
|
<Progress
|
|
|
|
|
value={value ? strengthScore + 1 : 0}
|
|
|
|
|
total={5}
|
|
|
|
|
color={STRENGTH_SCORE_COLORS[strengthScore]}
|
|
|
|
|
size="tiny"
|
|
|
|
|
className={styles.strengthBar}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
InputPassword.propTypes = {
|
|
|
|
|
value: PropTypes.string.isRequired,
|
|
|
|
|
withStrengthBar: PropTypes.bool,
|
|
|
|
|
minStrengthScore: PropTypes.number,
|
|
|
|
|
className: PropTypes.string,
|
2025-09-22 20:35:13 +02:00
|
|
|
onClear: PropTypes.func,
|
2022-09-03 22:47:06 +05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
InputPassword.defaultProps = {
|
|
|
|
|
withStrengthBar: false,
|
|
|
|
|
minStrengthScore: 2,
|
|
|
|
|
className: undefined,
|
2025-09-22 20:35:13 +02:00
|
|
|
onClear: undefined,
|
2022-09-03 22:47:06 +05:00
|
|
|
};
|
2019-11-15 03:45:59 +05:00
|
|
|
|
|
|
|
|
export default React.memo(InputPassword);
|