diff --git a/packages/kitchen-sink/src/examples/password-generator.tsx b/packages/kitchen-sink/src/examples/password-generator.tsx
new file mode 100644
index 0000000000..259822ff22
--- /dev/null
+++ b/packages/kitchen-sink/src/examples/password-generator.tsx
@@ -0,0 +1,238 @@
+import { useState, useEffect, useRef } from 'react';
+import { block } from 'million/react';
+import { BsClipboardCheck } from 'react-icons/bs';
+import { FiRefreshCcw } from 'react-icons/fi';
+
+const PasswordGenerator = block(() => {
+ const {
+ copyPasswordToClipboard,
+ password,
+ passwordInputRef,
+ setPassword,
+ generatePassword,
+ } = useGeneratePassword();
+ return (
+
+
Password Generator
+
+
+ Create strong and secure passwords to keep your account safe online.
+
+
+
+ {/* Password Generator Output */}
+
+
+
+
+
+
+
+
+
+
+
+ {/* Options */}
+
+
+
+
+ {
+ setPassword({
+ ...password,
+ length: parseInt(e.target.value),
+ });
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+ setPassword({ ...password, numbers: !password.numbers })
+ }
+ className="password_generator_customizable_options__checkbox"
+ />
+
+
+
+
+
+ setPassword({ ...password, symbols: !password.symbols })
+ }
+ className="password_generator_customizable_options__checkbox"
+ />
+
+
+
+
+
+ );
+});
+
+export default PasswordGenerator;
+
+const Tooltip = ({ text, children, show }: IToolTipProps) => {
+ return (
+
+
{children}
+
+ {text}
+
+
+ );
+};
+
+type IPasswordType = 'password' | 'pin';
+
+interface IPasswordState {
+ value: string;
+ password_type: IPasswordType;
+ length: number;
+ isCopied: boolean;
+ numbers?: boolean;
+ symbols?: boolean;
+}
+
+interface IToolTipProps {
+ children: JSX.Element;
+ text: string;
+ show: boolean;
+}
+
+interface IGeneratePassword {
+ includeNumbers: boolean;
+ includeSymbols: boolean;
+ passwordLength: number;
+ password_type: IPasswordType;
+}
+
+const useGeneratePassword = () => {
+ const passwordInputRef = useRef(null);
+
+ const [password, setPassword] = useState({
+ value: '',
+ password_type: 'password',
+ length: 3,
+ isCopied: false,
+ numbers: false,
+ symbols: false,
+ });
+
+ const copyPasswordToClipboard = () => {
+ if (passwordInputRef.current) {
+ passwordInputRef.current.select();
+ document.execCommand('copy');
+
+ // Deselect the text
+ window.getSelection()?.removeAllRanges();
+
+ setPassword({ ...password, isCopied: true });
+
+ setTimeout(() => {
+ setPassword({ ...password, isCopied: false });
+ }, 3000);
+ }
+ };
+
+ const generatePassword = () => {
+ const lowercaseChars = 'abcdefghijklmnopqrstuvwxyz';
+ const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ const numberChars = '0123456789';
+ const symbolChars = '!@#$%^&*()_+{}[]|:;"<>,.?/~';
+
+ let charset = '';
+
+ if (password.password_type === 'password') {
+ charset += lowercaseChars + uppercaseChars;
+
+ if (password.numbers) {
+ charset += numberChars;
+ }
+
+ if (password.symbols) {
+ charset += symbolChars;
+ }
+ }
+
+ if (password.password_type === 'pin') {
+ charset += numberChars;
+ }
+
+ let generatedValue = '';
+
+ for (let i = 0; i < password.length; i++) {
+ const randomIndex = Math.floor(Math.random() * charset.length);
+ generatedValue += charset[randomIndex];
+ }
+
+ setPassword({ ...password, value: generatedValue });
+ };
+
+ useEffect(() => {
+ generatePassword();
+ }, [
+ password.length,
+ password.numbers,
+ password.password_type,
+ password.symbols,
+ ]);
+
+ return {
+ passwordInputRef,
+ password,
+ setPassword,
+ copyPasswordToClipboard,
+ generatePassword,
+ };
+};
diff --git a/packages/kitchen-sink/src/style.css b/packages/kitchen-sink/src/style.css
index 21eed2e273..3a8f735648 100644
--- a/packages/kitchen-sink/src/style.css
+++ b/packages/kitchen-sink/src/style.css
@@ -222,3 +222,107 @@ input[type='range'] {
}
}
}
+
+/********** PASSWORD GENERATOR **********/
+.password_generator {
+ width: 80%;
+ margin: 2em auto;
+}
+
+.password_generator_top_section {
+ display: flex;
+ gap: 1.5em;
+}
+
+.password_generator_output_container {
+ display: flex;
+ border-radius: 10px;
+ background: #353535;
+ border: 1px solid #dddddd;
+ align-items: center;
+ padding-right: 20px;
+ flex: 5;
+}
+
+.password_generator_output_container input {
+ padding: 14px;
+ width: 100%;
+ outline: none;
+ line-height: 30px;
+ caret-color: #1c1c1c;
+ background-color: transparent;
+ font-size: 16px;
+ border-radius: 10px;
+ transition: all 0.3s ease-in;
+ color: #fff;
+ font-weight: 600;
+ font-size: 1.5rem;
+}
+
+.password_generator_output_container .right-icon {
+ font-size: 25px;
+ cursor: pointer;
+ border: none;
+}
+
+.password_generator_refresh_password {
+ flex: 0.5;
+}
+
+.password_generator_tooltip-container {
+ position: relative;
+}
+
+.password_generator_tooltip-text {
+ background-color: #333;
+ color: #fff;
+ text-align: center;
+ border-radius: 4px;
+ padding: 6px;
+ position: absolute;
+ z-index: 1;
+ bottom: 50%;
+ left: 90%;
+ font-size: 12px;
+ opacity: 0;
+ transition: all 200ms ease-in-out;
+}
+
+.password_generator_tooltip-text.visible {
+ opacity: 1;
+}
+
+.password_generator_customizable_options {
+}
+
+.password_generator_customizable_options__length {
+ display: flex;
+ align-items: center;
+}
+
+.password_generator_customizable_options__checkbox {
+ position: relative;
+ /* border: 1px solid themed("primary"); */
+ border-radius: 4px;
+ background: none;
+ cursor: pointer;
+ line-height: 0;
+ margin: 0 0.6em 0 0;
+ outline: 0;
+ padding: 0 !important;
+ vertical-align: text-top;
+ height: 18px;
+ width: 18px;
+ opacity: 0.5;
+ transition: all 200ms ease-in-out;
+
+ &:hover {
+ opacity: 1;
+ }
+
+ &:checked {
+ /* background-color: themed("primary"); */
+ opacity: 1;
+ border: none;
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c3ba176c47..2d710c2ac2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11235,4 +11235,4 @@ packages:
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
- dev: false
+ dev: false
\ No newline at end of file