<commit_before>// ─────────────────────────────────────────────────────────────────────────────
// import
// ─────────────────────────────────────────────────────────────────────────────

import React, { useState } from 'react';
import zxcvbn from 'zxcvbn';

import { Input } from '~components/primitives/Input';
import Dots from '~components/interactive/Dots';

// ─────────────────────────────────────────────────────────────────────────────
// component
// ─────────────────────────────────────────────────────────────────────────────

const defaultColors = Array.from({ length: 4 }, () => 'hsla(var(--hsl-text), 0.25)');

export default function TextInput({ onChange, type, ...rest }) {
  const [isHidden, setIsHidden] = useState(type === 'password');
  const [colors, setColors] = useState(defaultColors);

  const handleChange = (event) => {
    if (event.target.value === '') {
      return setColors(defaultColors);
    }

    const { score } = zxcvbn(event.target.value);

    if (onChange) {
      onChange(event);
    }

    return setColors(
      Array.from({ length: 4 }, (_, i) => {
        if (score < 2 && i === 3) return 'var(--color-danger)';
        if (score === 2 && i > 1) return 'var(--color-warning)';
        if (score === 3 && i > 0) return 'var(--color-success)';
        if (score === 4) return 'var(--color-success)';
        return 'hsla(var(--hsl-text), 0.25)';
      }),
    );
  };

  return (
    <>
      <Input type={isHidden ? type : 'text'} onChange={handleChange} {...rest} />
      <Dots
        position="absolute"
        top="2rem"
        right="1rem"
        amount="4"
        orientation="column"
        pointerEvents="none"
        colors={colors}
      />
    </>
  );
}
<commit_msg>add password input visibility button<commit_after>// ─────────────────────────────────────────────────────────────────────────────
// import
// ─────────────────────────────────────────────────────────────────────────────

import React, { useState, useRef } from 'react';
import { FaEye, FaEyeSlash } from 'react-icons/fa';
import zxcvbn from 'zxcvbn';

import { Input } from '~components/primitives/Input';
import { Icon } from '~components/multimedia/Icon';
import Dots from '~components/interactive/Dots';
import { Button } from '~components/interactive/Button';

// ─────────────────────────────────────────────────────────────────────────────
// helpers
// ─────────────────────────────────────────────────────────────────────────────

const defaultColors = Array.from({ length: 4 }, () => 'hsla(var(--hsl-text), 0.25)');

// ─────────────────────────────────────────────────────────────────────────────
// component
// ─────────────────────────────────────────────────────────────────────────────

export default function TextInput({ onChange, type, ...rest }) {
  const inputRef = useRef();
  const [isHidden, setIsHidden] = useState(type === 'password');
  const [colors, setColors] = useState(defaultColors);

  const handleChange = (event) => {
    if (event.target.value === '') {
      return setColors(defaultColors);
    }

    const { score } = zxcvbn(event.target.value);

    if (onChange) {
      onChange(event);
    }

    return setColors(
      Array.from({ length: 4 }, (_, i) => {
        if (score < 2 && i === 3) return 'var(--color-danger)';
        if (score === 2 && i > 1) return 'var(--color-warning)';
        if (score === 3 && i > 0) return 'var(--color-success)';
        if (score === 4) return 'var(--color-success)';
        return 'hsla(var(--hsl-text), 0.25)';
      }),
    );
  };

  const handleFocus = () => inputRef.current.focus();
  const handleVisibility = () => {
    handleFocus();
    setIsHidden(prev => !prev);
  };

  return (
    <>
      <Input ref={inputRef} type={isHidden ? type : 'text'} onChange={handleChange} {...rest} />
      <Button
        type="button"
        tertiary
        position="absolute"
        top="2.5rem"
        right="3rem"
        cursor="pointer"
        opacity="0.5"
        padding="0"
        hover={{
          opacity: '1',
          fill:    'var(--color-info)',
        }}
        onClick={handleVisibility}
      >
        <Icon as={isHidden ? FaEyeSlash : FaEye} />
      </Button>
      <Dots
        position="absolute"
        top="2rem"
        right="1rem"
        amount="4"
        orientation="column"
        pointerEvents="none"
        colors={colors}
      />
    </>
  );
}

{'fraction_non_alphanumeric': 0.3242019470228662, 'fraction_numerical': 0.009735114330993888, 'mean_word_length': 3.0907407407407406, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3390059', 'n_tokens_mistral': 1613, 'n_tokens_neox': 1310, 'n_words': 273}