feat(slice-3): design-system foundation — Wiggleverse tokens, fonts, brand marks, UI kit (per ui/designs export)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
// Six-cell one-time-code input: one real <input> (invisible, full-bleed) carries the value
|
||||
// and the OTC autofill semantics; the cells are presentation. Click anywhere to focus;
|
||||
// paste works because the input is real.
|
||||
import { useState } from "react";
|
||||
|
||||
const LENGTH = 6;
|
||||
|
||||
export default function CodeInput({
|
||||
value,
|
||||
onChange,
|
||||
error = false,
|
||||
}: {
|
||||
value: string;
|
||||
onChange: (code: string) => void;
|
||||
error?: boolean;
|
||||
}) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const digits = value.slice(0, LENGTH).split("");
|
||||
const active = Math.min(digits.length, LENGTH - 1);
|
||||
|
||||
return (
|
||||
<div className={`code${focused ? " code--focus" : ""}${error ? " code--error" : ""}`}>
|
||||
<input
|
||||
className="code__hidden"
|
||||
value={value}
|
||||
inputMode="numeric"
|
||||
autoComplete="one-time-code"
|
||||
aria-label="One-time code"
|
||||
autoFocus
|
||||
maxLength={LENGTH}
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={() => setFocused(false)}
|
||||
onChange={(ev) => onChange(ev.target.value.replace(/\D/g, "").slice(0, LENGTH))}
|
||||
/>
|
||||
{Array.from({ length: LENGTH }, (_, i) => (
|
||||
<span
|
||||
key={i}
|
||||
aria-hidden="true"
|
||||
className={`code__cell${i === active && focused ? " code__cell--active" : ""}`}
|
||||
>
|
||||
{digits[i] ?? ""}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user