Skip to content

Commit 454ecf0

Browse files
authored
feat: PinInput with input-otp demos and styles (#402)
1 parent 7af3b61 commit 454ecf0

24 files changed

+392
-46
lines changed

apps/www/__registry__/index.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,20 +549,41 @@ export const Index = {
549549
component: () => import("../src/lib/registry/default/example/PaginationDemo.vue").then((m) => m.default),
550550
files: ["../src/lib/registry/default/example/PaginationDemo.vue"],
551551
},
552+
"PinInputControlled": {
553+
name: "PinInputControlled",
554+
type: "components:example",
555+
registryDependencies: ["pin-input"],
556+
component: () => import("../src/lib/registry/default/example/PinInputControlled.vue").then((m) => m.default),
557+
files: ["../src/lib/registry/default/example/PinInputControlled.vue"],
558+
},
552559
"PinInputDemo": {
553560
name: "PinInputDemo",
554561
type: "components:example",
555562
registryDependencies: ["pin-input"],
556563
component: () => import("../src/lib/registry/default/example/PinInputDemo.vue").then((m) => m.default),
557564
files: ["../src/lib/registry/default/example/PinInputDemo.vue"],
558565
},
566+
"PinInputDisabled": {
567+
name: "PinInputDisabled",
568+
type: "components:example",
569+
registryDependencies: ["pin-input"],
570+
component: () => import("../src/lib/registry/default/example/PinInputDisabled.vue").then((m) => m.default),
571+
files: ["../src/lib/registry/default/example/PinInputDisabled.vue"],
572+
},
559573
"PinInputFormDemo": {
560574
name: "PinInputFormDemo",
561575
type: "components:example",
562576
registryDependencies: ["pin-input","button","form","toast"],
563577
component: () => import("../src/lib/registry/default/example/PinInputFormDemo.vue").then((m) => m.default),
564578
files: ["../src/lib/registry/default/example/PinInputFormDemo.vue"],
565579
},
580+
"PinInputSeparatorDemo": {
581+
name: "PinInputSeparatorDemo",
582+
type: "components:example",
583+
registryDependencies: ["pin-input"],
584+
component: () => import("../src/lib/registry/default/example/PinInputSeparatorDemo.vue").then((m) => m.default),
585+
files: ["../src/lib/registry/default/example/PinInputSeparatorDemo.vue"],
586+
},
566587
"PopoverDemo": {
567588
name: "PopoverDemo",
568589
type: "components:example",
@@ -1586,20 +1607,41 @@ export const Index = {
15861607
component: () => import("../src/lib/registry/new-york/example/PaginationDemo.vue").then((m) => m.default),
15871608
files: ["../src/lib/registry/new-york/example/PaginationDemo.vue"],
15881609
},
1610+
"PinInputControlled": {
1611+
name: "PinInputControlled",
1612+
type: "components:example",
1613+
registryDependencies: ["pin-input"],
1614+
component: () => import("../src/lib/registry/new-york/example/PinInputControlled.vue").then((m) => m.default),
1615+
files: ["../src/lib/registry/new-york/example/PinInputControlled.vue"],
1616+
},
15891617
"PinInputDemo": {
15901618
name: "PinInputDemo",
15911619
type: "components:example",
15921620
registryDependencies: ["pin-input"],
15931621
component: () => import("../src/lib/registry/new-york/example/PinInputDemo.vue").then((m) => m.default),
15941622
files: ["../src/lib/registry/new-york/example/PinInputDemo.vue"],
15951623
},
1624+
"PinInputDisabled": {
1625+
name: "PinInputDisabled",
1626+
type: "components:example",
1627+
registryDependencies: ["pin-input"],
1628+
component: () => import("../src/lib/registry/new-york/example/PinInputDisabled.vue").then((m) => m.default),
1629+
files: ["../src/lib/registry/new-york/example/PinInputDisabled.vue"],
1630+
},
15961631
"PinInputFormDemo": {
15971632
name: "PinInputFormDemo",
15981633
type: "components:example",
15991634
registryDependencies: ["pin-input","button","form","toast"],
16001635
component: () => import("../src/lib/registry/new-york/example/PinInputFormDemo.vue").then((m) => m.default),
16011636
files: ["../src/lib/registry/new-york/example/PinInputFormDemo.vue"],
16021637
},
1638+
"PinInputSeparatorDemo": {
1639+
name: "PinInputSeparatorDemo",
1640+
type: "components:example",
1641+
registryDependencies: ["pin-input"],
1642+
component: () => import("../src/lib/registry/new-york/example/PinInputSeparatorDemo.vue").then((m) => m.default),
1643+
files: ["../src/lib/registry/new-york/example/PinInputSeparatorDemo.vue"],
1644+
},
16031645
"PopoverDemo": {
16041646
name: "PopoverDemo",
16051647
type: "components:example",

apps/www/src/content/docs/components/pin-input.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ source: apps/www/src/lib/registry/default/ui/pin-input
55
primitive: https://www.radix-vue.com/components/pin-input.html
66
---
77

8-
<ComponentPreview name="PinInputDemo" />
9-
8+
<ComponentPreview name="PinInputDemo" />
109

1110
## Installation
1211

@@ -16,6 +15,18 @@ npx shadcn-vue@latest add pin-input
1615

1716
## Usage
1817

18+
### Controlled
19+
20+
<ComponentPreview name="PinInputControlled" />
21+
22+
### Disabled
23+
24+
<ComponentPreview name="PinInputDisabled" />
25+
26+
### Separator
27+
28+
<ComponentPreview name="PinInputSeparatorDemo" />
29+
1930
### Form
2031

21-
<ComponentPreview name="PinInputFormDemo" />
32+
<ComponentPreview name="PinInputFormDemo" />
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
import {
4+
PinInput,
5+
PinInputGroup,
6+
PinInputInput,
7+
} from '@/lib/registry/default/ui/pin-input'
8+
9+
const value = ref<string[]>(['1', '2', '3'])
10+
const handleComplete = (e: string[]) => alert(e.join(''))
11+
</script>
12+
13+
<template>
14+
<div>
15+
<PinInput
16+
id="pin-input"
17+
v-model="value"
18+
placeholder=""
19+
@complete="handleComplete"
20+
>
21+
<PinInputGroup>
22+
<PinInputInput
23+
v-for="(id, index) in 5"
24+
:key="id"
25+
:index="index"
26+
/>
27+
</PinInputGroup>
28+
</PinInput>
29+
</div>
30+
</template>

apps/www/src/lib/registry/default/example/PinInputDemo.vue

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { ref } from 'vue'
33
import {
44
PinInput,
5+
PinInputGroup,
56
PinInputInput,
67
} from '@/lib/registry/default/ui/pin-input'
78
@@ -15,14 +16,15 @@ const handleComplete = (e: string[]) => alert(e.join(''))
1516
id="pin-input"
1617
v-model="value"
1718
placeholder=""
18-
class="flex gap-2 items-center mt-1"
1919
@complete="handleComplete"
2020
>
21-
<PinInputInput
22-
v-for="(id, index) in 5"
23-
:key="id"
24-
:index="index"
25-
/>
21+
<PinInputGroup>
22+
<PinInputInput
23+
v-for="(id, index) in 5"
24+
:key="id"
25+
:index="index"
26+
/>
27+
</PinInputGroup>
2628
</PinInput>
2729
</div>
2830
</template>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
import {
4+
PinInput,
5+
PinInputGroup,
6+
PinInputInput,
7+
} from '@/lib/registry/default/ui/pin-input'
8+
9+
const value = ref<string[]>([])
10+
</script>
11+
12+
<template>
13+
<div>
14+
<PinInput
15+
id="pin-input"
16+
v-model="value"
17+
placeholder=""
18+
disabled
19+
>
20+
<PinInputGroup>
21+
<PinInputInput
22+
v-for="(id, index) in 5"
23+
:key="id"
24+
:index="index"
25+
/>
26+
</PinInputGroup>
27+
</PinInput>
28+
</div>
29+
</template>

apps/www/src/lib/registry/default/example/PinInputFormDemo.vue

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { toTypedSchema } from '@vee-validate/zod'
55
import * as z from 'zod'
66
import {
77
PinInput,
8+
PinInputGroup,
89
PinInputInput,
910
} from '@/lib/registry/default/ui/pin-input'
1011
import { Button } from '@/lib/registry/default/ui/button'
@@ -25,7 +26,7 @@ const formSchema = toTypedSchema(z.object({
2526
const { handleSubmit, setValues } = useForm({
2627
validationSchema: formSchema,
2728
initialValues: {
28-
pin: [],
29+
pin: ['1', '2', '3'],
2930
},
3031
})
3132
@@ -59,11 +60,13 @@ const handleComplete = (e: string[]) => console.log(e.join(''))
5960
})
6061
}"
6162
>
62-
<PinInputInput
63-
v-for="(id, index) in 5"
64-
:key="id"
65-
:index="index"
66-
/>
63+
<PinInputGroup>
64+
<PinInputInput
65+
v-for="(id, index) in 5"
66+
:key="id"
67+
:index="index"
68+
/>
69+
</PinInputGroup>
6770
</PinInput>
6871
</FormControl>
6972
<FormDescription>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
import {
4+
PinInput,
5+
PinInputGroup,
6+
PinInputInput,
7+
PinInputSeparator,
8+
} from '@/lib/registry/default/ui/pin-input'
9+
10+
const value = ref<string[]>([])
11+
const handleComplete = (e: string[]) => alert(e.join(''))
12+
</script>
13+
14+
<template>
15+
<div>
16+
<PinInput
17+
id="pin-input"
18+
v-model="value"
19+
placeholder=""
20+
@complete="handleComplete"
21+
>
22+
<PinInputGroup class="gap-1">
23+
<template v-for="(id, index) in 5" :key="id">
24+
<PinInputInput
25+
class="rounded-md border"
26+
:index="index"
27+
/>
28+
<template v-if="index !== 4">
29+
<PinInputSeparator />
30+
</template>
31+
</template>
32+
</PinInputGroup>
33+
</PinInput>
34+
</div>
35+
</template>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script setup lang="ts">
2+
import { type HTMLAttributes, computed } from 'vue'
3+
import { Primitive, type PrimitiveProps, useForwardProps } from 'radix-vue'
4+
import { cn } from '@/lib/utils'
5+
6+
const props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()
7+
const delegatedProps = computed(() => {
8+
const { class: _, ...delegated } = props
9+
return delegated
10+
})
11+
const forwardedProps = useForwardProps(delegatedProps)
12+
</script>
13+
14+
<template>
15+
<Primitive v-bind="forwardedProps" :class="cn('flex items-center', props.class)">
16+
<slot />
17+
</primitive>
18+
</template>

apps/www/src/lib/registry/default/ui/pin-input/PinInputInput.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ const forwardedProps = useForwardProps(delegatedProps)
1414
</script>
1515

1616
<template>
17-
<PinInputInput v-bind="forwardedProps" :class="cn('flex w-10 h-10 text-center rounded-md border border-input bg-background text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', props.class)" />
17+
<PinInputInput v-bind="forwardedProps" :class="cn('relative text-center focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md', props.class)" />
1818
</template>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script setup lang="ts">
2+
import { Primitive, type PrimitiveProps, useForwardProps } from 'radix-vue'
3+
import { Dot } from 'lucide-vue-next'
4+
5+
const props = defineProps<PrimitiveProps>()
6+
const forwardedProps = useForwardProps(props)
7+
</script>
8+
9+
<template>
10+
<Primitive v-bind="forwardedProps">
11+
<slot>
12+
<Dot />
13+
</slot>
14+
</primitive>
15+
</template>

0 commit comments

Comments
 (0)