InputOtp for Volt

pull/7377/head
Cagatay Civici 2025-03-05 14:02:38 +03:00
parent 59e1916e1f
commit 6699962b62
12 changed files with 392 additions and 23 deletions

View File

@ -50,6 +50,10 @@
"name": "InputNumber",
"to": "/inputnumber"
},
{
"name": "InputOtp",
"to": "/inputotp"
},
{
"name": "InputText",
"to": "/inputtext"

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>InputOtp is used with the <i>v-model</i> property for two-way value binding. The number of characters is defined with the <i>length</i> option, which is set to 4 by default.</p>
</DocSectionText>
<div class="card flex justify-center">
<InputOtp v-model="value" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<InputOtp v-model="value" />
</div>
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Specify the <i>variant</i> property as <i>filled</i> to display the component with a higher visual emphasis than the default <i>outlined</i> style.</p>
</DocSectionText>
<div class="card flex justify-center">
<InputOtp v-model="value" variant="filled" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<InputOtp v-model="value" variant="filled" />
</div>
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,11 @@
<template>
<DocSectionText v-bind="$attrs" />
<DocSectionCode :code="code" lang="script" />
</template>
<script setup>
import { ref } from 'vue';
const code = ref(`import InputOtp from '@/volt/inputotp';
`);
</script>

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>When <i>integerOnly</i> is present, only integers can be accepted as input.</p>
</DocSectionText>
<div class="card flex justify-center">
<InputOtp v-model="value" integerOnly />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<InputOtp v-model="value" integerOnly />
</div>
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,31 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Enable the <i>mask</i> option to hide the values in the input fields.</p>
</DocSectionText>
<div class="card flex justify-center">
<InputOtp v-model="value" mask />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<InputOtp v-model="value" mask />
</div>
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,72 @@
<template>
<DocSectionText v-bind="$attrs">
<p>A sample UI implementation with templating and additional elements.</p>
</DocSectionText>
<div class="card flex justify-center">
<div class="flex flex-col items-center">
<div class="font-bold text-xl mb-2">Authenticate Your Account</div>
<p class="text-surface-500 dark:text-surface-400 block mb-8">Please enter the code sent to your phone.</p>
<InputOtp v-model="value" :length="6" style="gap: 0">
<template #default="{ attrs, events, index }">
<input
type="text"
v-bind="attrs"
v-on="events"
class="w-12 h-12 text-2xl text-center border border-surface-200 :border-surface-700 focus:-outline-offset-2 focus:outline-2 focus:outline-primary border-r-0 text-surface-700 dark:text-surface-0 first:rounded-s-xl nth-5:rounded-s-xl last:rounded-e-xl nth-3:rounded-e-xl nth-3:border-r last:border-r"
/>
<div v-if="index === 3" class="px-4">
<i class="pi pi-minus" />
</div>
</template>
</InputOtp>
<div class="flex justify-between mt-8 self-stretch">
<Button label="Resend Code" variant="text" class="p-0"></Button>
<Button label="Submit Code"></Button>
</div>
</div>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import Button from '@/volt/button';
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<div class="flex flex-col items-center">
<div class="font-bold text-xl mb-2">Authenticate Your Account</div>
<p class="text-surface-500 dark:text-surface-400 block mb-8">Please enter the code sent to your phone.</p>
<InputOtp v-model="value" :length="6" style="gap: 0">
<template #default="{ attrs, events, index }">
<input
type="text"
v-bind="attrs"
v-on="events"
class="w-12 h-12 text-2xl text-center border border-surface-200 :border-surface-700 focus:-outline-offset-2 focus:outline-2 focus:outline-primary border-r-0 text-surface-700 dark:text-surface-0 first:rounded-s-xl nth-5:rounded-s-xl last:rounded-e-xl nth-3:rounded-e-xl nth-3:border-r last:border-r"
/>
<div v-if="index === 3" class="px-4">
<i class="pi pi-minus" />
</div>
</template>
</InputOtp>
<div class="flex justify-between mt-8 self-stretch">
<Button label="Resend Code" variant="text" class="p-0"></Button>
<Button label="Submit Code"></Button>
</div>
</div>
</div>
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,39 @@
<template>
<DocSectionText v-bind="$attrs">
<p>InputOtp provides <i>small</i> and <i>large</i> sizes as alternatives to the base.</p>
</DocSectionText>
<div class="card flex flex-col items-center gap-4">
<InputOtp v-model="value1" size="small" />
<InputOtp v-model="value2" />
<InputOtp v-model="value3" size="large" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value1 = ref(null);
const value2 = ref(null);
const value3 = ref(null);
const code = ref(`
<template>
<div class="card flex flex-col items-center gap-4">
<InputOtp v-model="value1" size="small" />
<InputOtp v-model="value2" />
<InputOtp v-model="value3" size="large" />
</div>
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value1 = ref(null);
const value2 = ref(null);
const value3 = ref(null);
<\/script>
`);
</script>

View File

@ -0,0 +1,39 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Define a template with your own UI elements with bindings to the provided events and attributes to replace the default design.</p>
</DocSectionText>
<div class="card flex justify-center">
<InputOtp v-model="value">
<template #default="{ attrs, events }">
<input type="text" v-bind="attrs" v-on="events" class="w-12 text-3xl border-x-0 border-y-0 text-center bg-transparent border-b-2 border-surface-300 dark:border-surface-700 focus:border-primary outline-none" />
</template>
</InputOtp>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<InputOtp v-model="value">
<template #default="{ attrs, events }">
<input type="text" v-bind="attrs" v-on="events" class="w-12 text-3xl border-x-0 border-y-0 text-center bg-transparent border-b-2 border-surface-300 dark:border-surface-700 focus:border-primary outline-none" />
</template>
</InputOtp>
</div>
</template>
<script setup>
import InputOtp from '@/volt/inputotp';
import { ref } from 'vue';
const value = ref(null);
<\/script>
`);
</script>

View File

@ -1,31 +1,11 @@
<template>
<DocSectionText v-bind="$attrs">
<p>InputText is used with the <i>v-model</i> property for two-way value binding.</p>
</DocSectionText>
<div class="card flex justify-center">
<InputText v-model="value" />
</div>
<DocSectionCode :code="code" />
<DocSectionText v-bind="$attrs" />
<DocSectionCode :code="code" lang="script" />
</template>
<script setup>
import InputText from '@/volt/inputtext';
import { ref } from 'vue';
const value = ref(null);
const code = ref(`
<template>
<div class="card flex justify-center">
<InputText v-model="value" />
</div>
</template>
<script setup>
import InputText from '@/volt/inputtext';
import { ref } from 'vue';
const value = ref(null);
<\/script>
const code = ref(`import InputText from '@/volt/inputtext';
`);
</script>

View File

@ -0,0 +1,58 @@
<template>
<DocComponent title="Vue Otp Input Component" header="InputOtp" description="Input Otp is used to enter one time passwords." :componentDocs="docs" />
</template>
<script setup>
import BasicDoc from '@/doc/inputotp/BasicDoc.vue';
import FilledDoc from '@/doc/inputotp/FilledDoc.vue';
import ImportDoc from '@/doc/inputotp/ImportDoc.vue';
import IntegerOnlyDoc from '@/doc/inputotp/IntegerOnlyDoc.vue';
import MaskDoc from '@/doc/inputotp/MaskDoc.vue';
import SampleDoc from '@/doc/inputotp/SampleDoc.vue';
import SizesDoc from '@/doc/inputotp/SizesDoc.vue';
import TemplateDoc from '@/doc/inputotp/TemplateDoc.vue';
import { ref } from 'vue';
const docs = ref([
{
id: 'import',
label: 'Import',
component: ImportDoc
},
{
id: 'basic',
label: 'Basic',
component: BasicDoc
},
{
id: 'mask',
label: 'Mask',
component: MaskDoc
},
{
id: 'integeronly',
label: 'Integer Only',
component: IntegerOnlyDoc
},
{
id: 'filled',
label: 'Filled',
component: FilledDoc
},
{
id: 'sizes',
label: 'Sizes',
component: SizesDoc
},
{
id: 'template',
label: 'Template',
component: TemplateDoc
},
{
id: 'sample',
label: 'Sample',
component: SampleDoc
}
]);
</script>

View File

@ -0,0 +1,42 @@
<template>
<InputOtp
unstyled
:pt="theme"
:ptOptions="{
mergeProps: ptViewMerge
}"
>
<template v-for="(_, slotName) in $slots" v-slot:[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps ?? {}" />
</template>
</InputOtp>
</template>
<script setup>
import InputOtp from 'primevue/inputotp';
import { ref } from 'vue';
import { ptViewMerge } from '../utils';
const theme = ref({
root: `flex items-center gap-2`,
pcInputText: {
root: `text-center w-12 h-12
appearance-none rounded-md outline-hidden
bg-surface-0 dark:bg-surface-950
p-filled:bg-surface-50 dark:p-filled:bg-surface-800
text-surface-700 dark:text-surface-0
placeholder:text-surface-500 dark:placeholder:text-surface-400
border border-surface-300 dark:border-surface-700
enabled:hover:border-surface-400 dark:enabled:hover:border-surface-600
enabled:focus:border-primary
disabled:bg-surface-200 disabled:text-surface-500
dark:disabled:bg-surface-700 dark:disabled:text-surface-400
p-invalid:border-red-400 dark:p-invalid:border-red-300
p-invalid:placeholder:text-red-600 dark:p-invalid:placeholder:text-red-400
px-3 py-2 p-fluid:w-full
p-small:text-sm p-small:px-[0.625rem] p-small-py-[0.375rem] p-small:w-10 p-small:h-10
p-large:text-xl p-small:px-[0.875rem] p-small-py-[0.625rem] p-large:w-14 p-large:h-14
transition-colors duration-200 shadow-[0_1px_2px_0_rgba(18,18,23,0.05)]`
}
});
</script>