├── .gitignore
├── src
├── components
│ ├── Xmark
│ │ ├── index.js
│ │ └── Xmark.js
│ ├── Checkmark
│ │ ├── index.js
│ │ └── Checkmark.js
│ ├── Requirement
│ │ ├── index.js
│ │ └── Requirement.js
│ └── Requirements
│ │ ├── index.js
│ │ └── Requirements.js
├── index.js
├── stories
│ ├── styles.css
│ └── Requirements.stories.js
└── styles.css
├── .storybook
├── preview.js
└── main.js
├── rollup.config.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
--------------------------------------------------------------------------------
/src/components/Xmark/index.js:
--------------------------------------------------------------------------------
1 | export * from './Xmark';
2 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export * from './components/Requirements';
2 |
--------------------------------------------------------------------------------
/src/components/Checkmark/index.js:
--------------------------------------------------------------------------------
1 | export * from './Checkmark';
2 |
--------------------------------------------------------------------------------
/src/components/Requirement/index.js:
--------------------------------------------------------------------------------
1 | export * from './Requirement';
2 |
--------------------------------------------------------------------------------
/src/components/Requirements/index.js:
--------------------------------------------------------------------------------
1 | export * from './Requirements';
2 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 |
2 | export const parameters = {
3 | actions: { argTypesRegex: "^on[A-Z].*" },
4 | }
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "stories": [
3 | "../src/**/*.stories.mdx",
4 | "../src/**/*.stories.@(js|jsx|ts|tsx)"
5 | ],
6 | "addons": [
7 | "@storybook/addon-links",
8 | "@storybook/addon-essentials"
9 | ]
10 | }
--------------------------------------------------------------------------------
/src/components/Checkmark/Checkmark.js:
--------------------------------------------------------------------------------
1 | // Ported from Alexander Haniotis' code here: https://codepen.io/haniotis/pen/KwvYLO
2 | import React from "react";
3 |
4 | export const Checkmark = () => {
5 | return (
6 |
22 | );
23 | }
--------------------------------------------------------------------------------
/src/components/Requirement/Requirement.js:
--------------------------------------------------------------------------------
1 | import { Xmark } from "../Xmark";
2 | import { Checkmark } from "../Checkmark";
3 | import React, { useEffect, useState } from "react";
4 |
5 | export const Requirement = ({ value, requirement }) => {
6 | const [isValid, setIsValid] = useState();
7 |
8 | useEffect(() => {
9 | setIsValid(requirement.validator(value));
10 | }, [value, requirement]);
11 |
12 | return (
13 |
14 | {isValid ?
:
}
15 |
16 |
17 | {requirement.text}
18 |
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/src/components/Requirements/Requirements.js:
--------------------------------------------------------------------------------
1 | import '../../styles.css';
2 | import { Requirement } from '../Requirement';
3 | import React, { useCallback, useEffect } from 'react';
4 |
5 | export const Requirements = ({
6 | value,
7 | requirements,
8 | onValidChange,
9 | }) => {
10 | const validChangeCb = useCallback(onValidChange, []);
11 |
12 | useEffect(() => {
13 | validChangeCb(
14 | requirements.every(r => r.validator(value))
15 | );
16 | }, [value, requirements, validChangeCb]);
17 |
18 | return requirements.map((r, index) => (
19 |
25 | ));
26 | };
27 |
--------------------------------------------------------------------------------
/src/stories/styles.css:
--------------------------------------------------------------------------------
1 | .form {
2 | width: 500px;
3 | padding: 25px;
4 | border-radius: 5px;
5 | padding-bottom: 50px;
6 | box-shadow: 0px 0px 5px gray;
7 | }
8 | .form input {
9 | width: 100%;
10 | border: none;
11 | padding: 8px;
12 | outline: none;
13 | margin-top: 25px;
14 | border-radius: 5px;
15 | box-sizing: border-box;
16 | box-shadow: 0px 0px 3px gray;
17 | }
18 | .form button {
19 | width: 100%;
20 | padding: 8px;
21 | border: none;
22 | outline: none;
23 | color: white;
24 | margin-top: 25px;
25 | border-radius: 5px;
26 | box-sizing: border-box;
27 | background-color: rgb(65, 65, 201);
28 | }
29 | .form button:disabled {
30 | cursor: not-allowed;
31 | background-color: lightgray;
32 | }
33 | .form h1 {
34 | font-family: sans-serif;
35 | }
36 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import resolve from '@rollup/plugin-node-resolve';
3 | import external from 'rollup-plugin-peer-deps-external';
4 | import { terser } from 'rollup-plugin-terser';
5 | import postcss from 'rollup-plugin-postcss';
6 |
7 | export default [
8 | {
9 | input: './src/index.js',
10 | output: [
11 | {
12 | file: 'dist/index.js',
13 | format: 'cjs',
14 | },
15 | {
16 | file: 'dist/index.es.js',
17 | format: 'es',
18 | exports: 'named',
19 | }
20 | ],
21 | plugins: [
22 | postcss({
23 | plugins: [],
24 | minimize: true,
25 | }),
26 | babel({
27 | exclude: 'node_modules/**',
28 | presets: ['@babel/preset-react']
29 | }),
30 | external(),
31 | resolve(),
32 | terser(),
33 | ]
34 | }
35 | ];
36 |
--------------------------------------------------------------------------------
/src/components/Xmark/Xmark.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export const Xmark = () => {
4 | return (
5 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | .requirement {
2 | height: 35px;
3 | display: flex;
4 | align-items: center;
5 | }
6 | .requirement p {
7 | font-size: 14px;
8 | margin-left: 10px;
9 | font-weight: bold;
10 | font-family: sans-serif;
11 | }
12 | .invalid {
13 | color: red;
14 | }
15 | .valid {
16 | color: #7ac142;
17 | }
18 |
19 | /* Ported from Alexander Haniotis' code here: https://codepen.io/haniotis/pen/KwvYLO */
20 | .checkmark {
21 | width: 15px;
22 | height: 15px;
23 | border-radius: 50%;
24 | display: block;
25 | stroke-width: 5;
26 | stroke: #fff;
27 | stroke-miterlimit: 10;
28 | box-shadow: inset 0px 0px 0px #7ac142;
29 | animation: fill .4s ease-in-out .4s forwards, scale .3s ease-in-out .9s both;
30 | }
31 |
32 | .checkmark__circle {
33 | stroke-dasharray: 166;
34 | stroke-dashoffset: 166;
35 | stroke-width: 2;
36 | stroke-miterlimit: 10;
37 | stroke: #7ac142;
38 | fill: none;
39 | animation: stroke .6s cubic-bezier(0.650, 0.000, 0.450, 1.000) forwards;
40 | }
41 |
42 | .checkmark__check {
43 | transform-origin: 50% 50%;
44 | stroke-dasharray: 48;
45 | stroke-dashoffset: 48;
46 | animation: stroke .2s cubic-bezier(0.650, 0.000, 0.450, 1.000) .5s forwards;
47 | }
48 |
49 | @keyframes stroke {
50 | 100% {
51 | stroke-dashoffset: 0;
52 | }
53 | }
54 |
55 | @keyframes scale {
56 | 0%, 100% {
57 | transform: none;
58 | }
59 | 50% {
60 | transform: scale3d(1.1, 1.1, 1);
61 | }
62 | }
63 |
64 | @keyframes fill {
65 | 100% {
66 | box-shadow: inset 0px 0px 0px 30px #7ac142;
67 | }
68 | }
--------------------------------------------------------------------------------
/src/stories/Requirements.stories.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import './styles.css';
4 | import { Requirements } from '../components/Requirements';
5 |
6 | const stories = storiesOf('App Test', module);
7 |
8 | stories.add('App', () => {
9 | const [valid, setValid] = useState(false);
10 | const [password, setPassword] = useState('');
11 | const [username, setUsername] = useState('');
12 |
13 | const passwordRequirements = [
14 | {
15 | text: 'Must be at least 8 characters',
16 | validator: val => val.length >= 8,
17 | },
18 | {
19 | text: 'Must contain at least one number',
20 | validator: val => /\d/g.test(val),
21 | },
22 | {
23 | text: 'Must contain at least one lower-case letter',
24 | validator: val => /[a-z]/g.test(val),
25 | },
26 | {
27 | text: 'Must contain at least one upper-case letter',
28 | validator: val => /[A-Z]/g.test(val),
29 | }
30 | ];
31 |
32 | return (
33 |
34 |
Signup
35 |
36 | setValid(isValid)}
40 | />
41 |
42 | setUsername(e.target.value)} />
43 | setPassword(e.target.value)} />
44 |
45 |
46 |
47 | );
48 | });
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-password-validator",
3 | "version": "1.0.0",
4 | "description": "A simple react component that accept password and validate it for more easy useage",
5 | "main": "dist/index.js",
6 | "module": "dist/index.es.js",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "storybook": "start-storybook -p 6006",
10 | "build-storybook": "build-storybook",
11 | "build-lib": "rollup -c"
12 | },
13 | "author": "Alan Binu",
14 | "license": "MIT",
15 | "devDependencies": {
16 | "@babel/core": "^7.12.10",
17 | "@babel/preset-react": "^7.12.10",
18 | "@rollup/plugin-node-resolve": "^11.1.1",
19 | "@storybook/addon-actions": "^6.1.16",
20 | "@storybook/addon-essentials": "^6.1.16",
21 | "@storybook/addon-links": "^6.1.16",
22 | "@storybook/react": "^6.1.16",
23 | "babel-loader": "^8.2.2",
24 | "react": "^17.0.1",
25 | "react-dom": "^17.0.1",
26 | "rollup": "^2.38.4",
27 | "rollup-plugin-babel": "^4.4.0",
28 | "rollup-plugin-peer-deps-external": "^2.2.4",
29 | "rollup-plugin-postcss": "^4.0.0",
30 | "rollup-plugin-terser": "^7.0.2"
31 | },
32 | "peerDependencies": {
33 | "react": "^17.0.1",
34 | "react-dom": "^17.0.1"
35 | },
36 |
37 | "repository": {
38 | "type": "git",
39 | "url": "git+https://github.com/benawad/tsconfig.json.git"
40 | },
41 | "bugs": {
42 | "url": "https://github.com/benawad/tsconfig.json/issues"
43 | },
44 | "publishConfig": {
45 | "access": "public",
46 | "branches": [
47 | "master"
48 | ]
49 | },
50 | "homepage": "https://github.com/benawad/tsconfig.json#readme",
51 | "dependencies": {}
52 | }
53 |
--------------------------------------------------------------------------------