ViraStack
  • Akademi
  • Hakkında
  • Destek
Genel BakışBaşlangıçÖrnekler

Başlangıç

  • Giriş
  • 1.0'dan geçiş
  • llms.txt
  • llms-full.txt

Kullanım

  • useViraPassword()
  • Güç
  • Parola tekrarı
  • React Hook Form
  • Erişilebilirlik
  • Özelleştirme

Sunucu

  • Sunucu doğrulaması
  • Sızmış parolalar

Başvuru

  • Yardımcılar
  • Tipler
  • UI kütüphaneleri
  • Karşılaştırma

React Hook Form

Hook'u register, Controller, Zod ve ViraStack Mask ile aynı formda kullanın.

React Hook Form tek doğruluk kaynağı olarak kalır. Hook yalnızca input'a props ekler; form değerini hiçbir zaman tutmaz.

register()

const { inputProps, btnProps, rule } = useViraPassword({ policy, value: password })
 
// inputProps yalnızca öznitelik taşır: register()'dan önce ya da sonra spread edin
<input {...inputProps} {...form.register("password", rule)} />
<button {...btnProps} />

useWatch()

reset() ve setValue() input olayı tetiklemeden değeri değiştirir. Güç ve matches bunları takip etsin diye value verin. useWatch, watch()'tan farklı olarak React Compiler ile de çalışır.

const password = useWatch({ control: form.control, name: "password" })
const { inputProps, strength } = useViraPassword({ policy, value: password })

rule & deps

rule ilk hata anahtarını döndürür. deps, parola değişince tekrar alanını yeniden doğrular.

form.register("password", { ...rule, deps: ["confirm"] })
 
// deps yalnızca kullanıcı girişinde çalışır. setValue'dan sonra tekrar alanını siz kontrol edin:
form.setValue("password", next)
form.trigger("confirm")

Forma method="post" verin. Hydration'dan önce form yerel olarak gönderilir ve varsayılan GET parolayı URL'ye yazar.

Controller

<Controller
  control={form.control}
  name="password"
  render={({ field }) => <PasswordField field={field} />}
/>
 
function PasswordField({ field }: { field: ControllerRenderProps<Values, "password"> }) {
  const { inputProps } = useViraPassword({
    policy,
    value: field.value,
    inputProps: { ...field, onChange: (e) => field.onChange(e.target.value) },
  })
  return <input {...inputProps} />
}

Zod resolver

Resolver varken register kuralları çalışmaz. Aynı politikayı evaluate ile Zod şemasına koyun:

// components/signup-form.tsx
"use client";
 
import { useState } from "react";
 
import { zodResolver } from "@hookform/resolvers/zod";
import { useViraPassword } from "@virastack/password";
import { evaluate, type PasswordIssue } from "@virastack/password/strength";
import { useForm, useWatch } from "react-hook-form";
import { z } from "zod";
 
import { passwordMessages } from "@/lib/password-messages";
import { policy } from "@/lib/password-policy";
 
// The same policy inside a Zod schema: errors are keys, messages come from your map.
const schema = z
  .object({ password: z.string(), confirm: z.string() })
  .superRefine(({ password, confirm }, ctx) => {
    for (const issue of evaluate(password, policy).issues) {
      ctx.addIssue({ code: "custom", path: ["password"], message: issue });
    }
    if (confirm !== password) {
      ctx.addIssue({ code: "custom", path: ["confirm"], message: "password.mismatch" });
    }
  });
 
export function SignupForm() {
  const [submitted, setSubmitted] = useState(false);
  const form = useForm({
    resolver: zodResolver(schema),
    defaultValues: { password: "", confirm: "" },
  });
  const { errors } = form.formState;
 
  // value from useWatch: reset() and setValue() don't fire input events.
  const password = useWatch({ control: form.control, name: "password" });
  const { inputProps, btnProps } = useViraPassword({ policy, value: password });
  const { inputProps: confirmProps, btnProps: confirmButton } = useViraPassword({
    matchWith: password,
  });
 
  return (
    <form method="post" onSubmit={form.handleSubmit(() => setSubmitted(true))}>
      <label htmlFor={inputProps.id}>New password</label>
      <div>
        <input {...inputProps} {...form.register("password")} />
        <button {...btnProps} />
      </div>
      {errors.password && (
        <p role="alert">{passwordMessages[errors.password.message as PasswordIssue]}</p>
      )}
 
      <label htmlFor={confirmProps.id}>Confirm password</label>
      <div>
        <input {...confirmProps} {...form.register("confirm")} />
        <button {...confirmButton} />
      </div>
      {errors.confirm && (
        <p role="alert">{passwordMessages[errors.confirm.message as PasswordIssue]}</p>
      )}
 
      <div>
        <button type="submit">Create account</button>
        <button type="button" onClick={() => (form.reset(), setSubmitted(false))}>
          Reset
        </button>
      </div>
      {submitted && <p>Valid. The password was hidden on submit.</p>}
    </form>
  );
}

Mask ile

ViraStack Mask v2 de değeri React Hook Form'da tutar; ikisi aynı useForm'u paylaşır. Farklı input'larda kullanın, asla aynı input'ta değil.

// components/signup-form.tsx
"use client";
 
import { useState } from "react";
 
import { useViraMask } from "@virastack/mask";
import { useViraPassword } from "@virastack/password";
import { useForm, useWatch } from "react-hook-form";
 
import { passwordMessages } from "@/lib/password-messages";
import { policy } from "@/lib/password-policy";
 
type Values = { phone: string; password: string; confirm: string };
 
export function SignupForm() {
  const [values, setValues] = useState<Values | null>(null);
  // One form: React Hook Form holds every value. Mask and Password go on different inputs.
  const form = useForm<Values>({ defaultValues: { phone: "", password: "", confirm: "" } });
  const { phone } = useViraMask(form, { phone: { preset: "phone", country: "TR" } });
  const { errors } = form.formState;
 
  const password = useWatch({ control: form.control, name: "password" });
  const { inputProps, btnProps, rule, issues } = useViraPassword({ policy, value: password });
  const {
    inputProps: confirmProps,
    btnProps: confirmButton,
    rule: confirmRule,
  } = useViraPassword({ matchWith: password });
 
  return (
    <form method="post" onSubmit={form.handleSubmit(setValues)}>
      <label htmlFor="phone">Phone</label>
      <input id="phone" {...phone} placeholder="(555) 123 45 67" />
 
      <label htmlFor={inputProps.id}>New password</label>
      <div>
        {/* deps: re-check the confirm field when the password changes */}
        <input {...inputProps} {...form.register("password", { ...rule, deps: ["confirm"] })} />
        <button {...btnProps} />
      </div>
      {errors.password && <p role="alert">{passwordMessages[issues[0] ?? "password.tooShort"]}</p>}
 
      <label htmlFor={confirmProps.id}>Confirm password</label>
      <div>
        <input {...confirmProps} {...form.register("confirm", confirmRule)} />
        <button {...confirmButton} />
      </div>
      {errors.confirm && <p role="alert">{passwordMessages["password.mismatch"]}</p>}
 
      <button type="submit">Sign up</button>
      {values && (
        <pre>
          {JSON.stringify({ phone: values.phone, password: "•".repeat(values.password.length) })}
        </pre>
      )}
    </form>
  );
}
ÖncekiParola tekrarıSonrakiErişilebilirlik

Bu sayfada

  • register()
  • useWatch()
  • rule & deps
  • Controller
  • Zod resolver
  • Mask ile
Hata mı var? Düzeltin