mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-24 01:03:50 +02:00
add OtpDialogModal
This commit is contained in:
78
src/components/ui/input-otp/InputOTP.vue
Normal file
78
src/components/ui/input-otp/InputOTP.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<script setup>
|
||||
import { OTPInput } from 'vue-input-otp';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { reactiveOmit } from '@vueuse/core';
|
||||
import { useForwardPropsEmits } from 'reka-ui';
|
||||
|
||||
const props = defineProps({
|
||||
maxlength: { type: Number, required: true },
|
||||
textAlign: { type: String, required: false },
|
||||
inputmode: { type: String, required: false },
|
||||
containerClass: { type: String, required: false },
|
||||
pushPasswordManagerStrategy: { type: String, required: false },
|
||||
noScriptCssFallback: { type: [String, null], required: false },
|
||||
defaultValue: { type: null, required: false },
|
||||
pasteTransformer: { type: Function, required: false },
|
||||
accept: { type: String, required: false },
|
||||
alt: { type: String, required: false },
|
||||
autocomplete: { type: String, required: false },
|
||||
autofocus: { type: Boolean, required: false },
|
||||
capture: { type: [Boolean, String], required: false },
|
||||
checked: { type: [Boolean, Array, Set], required: false },
|
||||
crossorigin: { type: String, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
enterKeyHint: { type: String, required: false },
|
||||
form: { type: String, required: false },
|
||||
formaction: { type: String, required: false },
|
||||
formenctype: { type: String, required: false },
|
||||
formmethod: { type: String, required: false },
|
||||
formnovalidate: { type: Boolean, required: false },
|
||||
formtarget: { type: String, required: false },
|
||||
height: { type: Number, required: false },
|
||||
indeterminate: { type: Boolean, required: false },
|
||||
list: { type: String, required: false },
|
||||
max: { type: Number, required: false },
|
||||
min: { type: Number, required: false },
|
||||
minlength: { type: Number, required: false },
|
||||
multiple: { type: Boolean, required: false },
|
||||
name: { type: String, required: false },
|
||||
pattern: { type: String, required: false },
|
||||
placeholder: { type: String, required: false },
|
||||
readonly: { type: Boolean, required: false },
|
||||
required: { type: Boolean, required: false },
|
||||
size: { type: Number, required: false },
|
||||
src: { type: String, required: false },
|
||||
step: { type: Number, required: false },
|
||||
type: { type: String, required: false },
|
||||
value: { type: null, required: false },
|
||||
width: { type: Number, required: false },
|
||||
class: { type: null, required: false }
|
||||
});
|
||||
|
||||
const emits = defineEmits([
|
||||
'complete',
|
||||
'change',
|
||||
'select',
|
||||
'input',
|
||||
'focus',
|
||||
'blur',
|
||||
'mouseover',
|
||||
'mouseleave',
|
||||
'paste'
|
||||
]);
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class');
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OTPInput
|
||||
v-slot="slotProps"
|
||||
v-bind="forwarded"
|
||||
:container-class="cn('flex items-center gap-2 has-disabled:opacity-50', props.class)"
|
||||
data-slot="input-otp"
|
||||
class="disabled:cursor-not-allowed">
|
||||
<slot v-bind="slotProps" />
|
||||
</OTPInput>
|
||||
</template>
|
||||
19
src/components/ui/input-otp/InputOTPGroup.vue
Normal file
19
src/components/ui/input-otp/InputOTPGroup.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
import { cn } from '@/lib/utils';
|
||||
import { reactiveOmit } from '@vueuse/core';
|
||||
import { useForwardProps } from 'reka-ui';
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false }
|
||||
});
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class');
|
||||
|
||||
const forwarded = useForwardProps(delegatedProps);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div data-slot="input-otp-group" v-bind="forwarded" :class="cn('flex items-center', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
18
src/components/ui/input-otp/InputOTPSeparator.vue
Normal file
18
src/components/ui/input-otp/InputOTPSeparator.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { MinusIcon } from 'lucide-vue-next';
|
||||
import { useForwardProps } from 'reka-ui';
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: null, required: false }
|
||||
});
|
||||
|
||||
const forwarded = useForwardProps(props);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div data-slot="input-otp-separator" role="separator" v-bind="forwarded">
|
||||
<slot>
|
||||
<MinusIcon />
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
38
src/components/ui/input-otp/InputOTPSlot.vue
Normal file
38
src/components/ui/input-otp/InputOTPSlot.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script setup>
|
||||
import { cn } from '@/lib/utils';
|
||||
import { computed } from 'vue';
|
||||
import { reactiveOmit } from '@vueuse/core';
|
||||
import { useForwardProps } from 'reka-ui';
|
||||
import { useVueOTPContext } from 'vue-input-otp';
|
||||
|
||||
const props = defineProps({
|
||||
index: { type: Number, required: true },
|
||||
class: { type: null, required: false }
|
||||
});
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class');
|
||||
|
||||
const forwarded = useForwardProps(delegatedProps);
|
||||
|
||||
const context = useVueOTPContext();
|
||||
|
||||
const slot = computed(() => context?.value.slots[props.index]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-bind="forwarded"
|
||||
data-slot="input-otp-slot"
|
||||
:data-active="slot?.isActive"
|
||||
:class="
|
||||
cn(
|
||||
'data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]',
|
||||
props.class
|
||||
)
|
||||
">
|
||||
{{ slot?.char }}
|
||||
<div v-if="slot?.hasFakeCaret" class="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||
<div class="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
4
src/components/ui/input-otp/index.js
Normal file
4
src/components/ui/input-otp/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export { default as InputOTP } from './InputOTP.vue';
|
||||
export { default as InputOTPGroup } from './InputOTPGroup.vue';
|
||||
export { default as InputOTPSeparator } from './InputOTPSeparator.vue';
|
||||
export { default as InputOTPSlot } from './InputOTPSlot.vue';
|
||||
Reference in New Issue
Block a user