mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-07-01 00:24:20 +00:00
* feat: add phosphor icons to base ui * feat_ add phosphor to blocks * feat: add phosphor to radix blocks * feat: add phosphor to radix ui * feat: add phosphor to radix example * feat: add missing phosphor icons * fix: rename broken icons * chore: format files * fix: add missing phosphor icons * chore: build registry --------- Co-authored-by: shadcn <m@shadcn.com>
292 lines
9.3 KiB
TypeScript
292 lines
9.3 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
import { REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
|
|
|
|
import {
|
|
Example,
|
|
ExampleWrapper,
|
|
} from "@/registry/bases/base/components/example"
|
|
import { Button } from "@/registry/bases/base/ui/button"
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardFooter,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/registry/bases/base/ui/card"
|
|
import {
|
|
Field,
|
|
FieldDescription,
|
|
FieldError,
|
|
FieldLabel,
|
|
} from "@/registry/bases/base/ui/field"
|
|
import {
|
|
InputOTP,
|
|
InputOTPGroup,
|
|
InputOTPSeparator,
|
|
InputOTPSlot,
|
|
} from "@/registry/bases/base/ui/input-otp"
|
|
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
|
|
|
export default function InputOTPExample() {
|
|
return (
|
|
<ExampleWrapper>
|
|
<InputOTPForm />
|
|
<InputOTPSimple />
|
|
<InputOTPPattern />
|
|
<InputOTPWithSeparator />
|
|
<InputOTPAlphanumeric />
|
|
<InputOTPDisabled />
|
|
<InputOTPFourDigits />
|
|
<InputOTPInvalid />
|
|
</ExampleWrapper>
|
|
)
|
|
}
|
|
|
|
function InputOTPSimple() {
|
|
return (
|
|
<Example title="Simple">
|
|
<Field>
|
|
<FieldLabel htmlFor="simple">Simple</FieldLabel>
|
|
<InputOTP id="simple" maxLength={6}>
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={0} />
|
|
<InputOTPSlot index={1} />
|
|
<InputOTPSlot index={2} />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={3} />
|
|
<InputOTPSlot index={4} />
|
|
<InputOTPSlot index={5} />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
</Field>
|
|
</Example>
|
|
)
|
|
}
|
|
|
|
function InputOTPPattern() {
|
|
return (
|
|
<Example title="Digits Only">
|
|
<Field>
|
|
<FieldLabel htmlFor="digits-only">Digits Only</FieldLabel>
|
|
<InputOTP id="digits-only" maxLength={6} pattern={REGEXP_ONLY_DIGITS}>
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={0} />
|
|
<InputOTPSlot index={1} />
|
|
<InputOTPSlot index={2} />
|
|
<InputOTPSlot index={3} />
|
|
<InputOTPSlot index={4} />
|
|
<InputOTPSlot index={5} />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
</Field>
|
|
</Example>
|
|
)
|
|
}
|
|
|
|
function InputOTPWithSeparator() {
|
|
const [value, setValue] = React.useState("123456")
|
|
|
|
return (
|
|
<Example title="With Separator">
|
|
<Field>
|
|
<FieldLabel htmlFor="with-separator">With Separator</FieldLabel>
|
|
<InputOTP
|
|
id="with-separator"
|
|
maxLength={6}
|
|
value={value}
|
|
onChange={setValue}
|
|
>
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={0} />
|
|
<InputOTPSlot index={1} />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={2} />
|
|
<InputOTPSlot index={3} />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={4} />
|
|
<InputOTPSlot index={5} />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
</Field>
|
|
</Example>
|
|
)
|
|
}
|
|
|
|
function InputOTPAlphanumeric() {
|
|
return (
|
|
<Example title="Alphanumeric">
|
|
<Field>
|
|
<FieldLabel htmlFor="alphanumeric">Alphanumeric</FieldLabel>
|
|
<FieldDescription>Accepts both letters and numbers.</FieldDescription>
|
|
<InputOTP
|
|
id="alphanumeric"
|
|
maxLength={6}
|
|
pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
|
|
>
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={0} />
|
|
<InputOTPSlot index={1} />
|
|
<InputOTPSlot index={2} />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={3} />
|
|
<InputOTPSlot index={4} />
|
|
<InputOTPSlot index={5} />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
</Field>
|
|
</Example>
|
|
)
|
|
}
|
|
|
|
function InputOTPDisabled() {
|
|
return (
|
|
<Example title="Disabled">
|
|
<Field>
|
|
<FieldLabel htmlFor="disabled">Disabled</FieldLabel>
|
|
<InputOTP id="disabled" maxLength={6} disabled value="123456">
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={0} />
|
|
<InputOTPSlot index={1} />
|
|
<InputOTPSlot index={2} />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={3} />
|
|
<InputOTPSlot index={4} />
|
|
<InputOTPSlot index={5} />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
</Field>
|
|
</Example>
|
|
)
|
|
}
|
|
|
|
function InputOTPFourDigits() {
|
|
return (
|
|
<Example title="4 Digits">
|
|
<Field>
|
|
<FieldLabel htmlFor="four-digits">4 Digits</FieldLabel>
|
|
<FieldDescription>Common pattern for PIN codes.</FieldDescription>
|
|
<InputOTP id="four-digits" maxLength={4} pattern={REGEXP_ONLY_DIGITS}>
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={0} />
|
|
<InputOTPSlot index={1} />
|
|
<InputOTPSlot index={2} />
|
|
<InputOTPSlot index={3} />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
</Field>
|
|
</Example>
|
|
)
|
|
}
|
|
|
|
function InputOTPInvalid() {
|
|
const [value, setValue] = React.useState("000000")
|
|
|
|
return (
|
|
<Example title="Invalid State">
|
|
<Field>
|
|
<FieldLabel htmlFor="invalid">Invalid State</FieldLabel>
|
|
<FieldDescription>
|
|
Example showing the invalid error state.
|
|
</FieldDescription>
|
|
<InputOTP id="invalid" maxLength={6} value={value} onChange={setValue}>
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={0} aria-invalid />
|
|
<InputOTPSlot index={1} aria-invalid />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={2} aria-invalid />
|
|
<InputOTPSlot index={3} aria-invalid />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup>
|
|
<InputOTPSlot index={4} aria-invalid />
|
|
<InputOTPSlot index={5} aria-invalid />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
<FieldError errors={[{ message: "Invalid code. Please try again." }]} />
|
|
</Field>
|
|
</Example>
|
|
)
|
|
}
|
|
|
|
function InputOTPForm() {
|
|
return (
|
|
<Example title="Form">
|
|
<Card className="mx-auto max-w-md">
|
|
<CardHeader>
|
|
<CardTitle>Verify your login</CardTitle>
|
|
<CardDescription>
|
|
Enter the verification code we sent to your email address:{" "}
|
|
<span className="font-medium">m@example.com</span>.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form>
|
|
<Field>
|
|
<div className="flex items-center justify-between">
|
|
<FieldLabel htmlFor="otp-verification">
|
|
Verification code
|
|
</FieldLabel>
|
|
<Button variant="outline" size="xs">
|
|
<IconPlaceholder
|
|
lucide="RefreshCwIcon"
|
|
hugeicons="RefreshIcon"
|
|
tabler="IconRefresh"
|
|
phosphor="ArrowClockwiseIcon"
|
|
data-icon="inline-start"
|
|
/>
|
|
Resend Code
|
|
</Button>
|
|
</div>
|
|
<InputOTP maxLength={6} id="otp-verification" required>
|
|
<InputOTPGroup className="style-nova:*:data-[slot=input-otp-slot]:h-12 style-nova:*:data-[slot=input-otp-slot]:w-11 style-vega:*:data-[slot=input-otp-slot]:h-16 style-maia:*:data-[slot=input-otp-slot]:h-16 style-vega:*:data-[slot=input-otp-slot]:w-12 style-maia:*:data-[slot=input-otp-slot]:w-12 style-mira:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:w-11 style-mira:*:data-[slot=input-otp-slot]:w-11 *:data-[slot=input-otp-slot]:text-xl">
|
|
<InputOTPSlot index={0} />
|
|
<InputOTPSlot index={1} />
|
|
<InputOTPSlot index={2} />
|
|
</InputOTPGroup>
|
|
<InputOTPSeparator />
|
|
<InputOTPGroup className="style-nova:*:data-[slot=input-otp-slot]:h-12 style-nova:*:data-[slot=input-otp-slot]:w-11 style-vega:*:data-[slot=input-otp-slot]:h-16 style-maia:*:data-[slot=input-otp-slot]:h-16 style-vega:*:data-[slot=input-otp-slot]:w-12 style-maia:*:data-[slot=input-otp-slot]:w-12 style-mira:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:w-11 style-mira:*:data-[slot=input-otp-slot]:w-11 *:data-[slot=input-otp-slot]:text-xl">
|
|
<InputOTPSlot index={3} />
|
|
<InputOTPSlot index={4} />
|
|
<InputOTPSlot index={5} />
|
|
</InputOTPGroup>
|
|
</InputOTP>
|
|
<FieldDescription>
|
|
<a href="#">I no longer have access to this email address.</a>
|
|
</FieldDescription>
|
|
</Field>
|
|
</form>
|
|
</CardContent>
|
|
<CardFooter className="flex-col gap-2">
|
|
<Button type="submit" className="w-full">
|
|
Verify
|
|
</Button>
|
|
<div className="text-muted-foreground text-sm">
|
|
Having trouble signing in?{" "}
|
|
<a
|
|
href="#"
|
|
className="hover:text-primary underline underline-offset-4 transition-colors"
|
|
>
|
|
Contact support
|
|
</a>
|
|
</div>
|
|
</CardFooter>
|
|
</Card>
|
|
</Example>
|
|
)
|
|
}
|