@coreui/vue-pro
Version:
UI Components Library for Vue.js
215 lines (186 loc) • 5.33 kB
text/typescript
// CPasswordInput.ts
import { defineComponent, h, ref, toRefs, watch, computed } from 'vue'
import { CFormControlWrapper } from '../form/CFormControlWrapper'
export const CPasswordInput = defineComponent({
name: 'CPasswordInput',
inheritAttrs: false,
props: {
/**
* Accessible label for the toggle visibility button.
*/
ariaLabelToggler: {
type: String,
default: 'Toggle password visibility',
},
/**
* Delay emitting `change` and `update:modelValue` events.
* `true` = 500ms delay, or specify custom delay in ms.
*/
delay: {
type: [Boolean, Number],
default: false,
},
/**
* Disables the password input field. When `true`, the user cannot interact with the field.
*/
disabled: Boolean,
/**
* General feedback text shown below the input.
*/
feedback: String,
/**
* Feedback text shown when input is invalid.
*/
feedbackInvalid: String,
/**
* Feedback text shown when input is valid.
*/
feedbackValid: String,
/**
* Class for the floating label wrapper.
*/
floatingClassName: String,
/**
* Floating label text.
*/
floatingLabel: String,
/**
* ID of the input element.
*/
id: String,
/**
* Marks the input as invalid.
*/
invalid: Boolean,
/**
* Main label for the input.
*/
label: String,
/**
* The current value of the password input, used with v-model.
*/
modelValue: String,
/**
* Makes the input read-only, allowing text selection only.
*/
readOnly: Boolean,
/**
* Controls the initial visibility of the password.
*/
showPassword: Boolean,
/**
* Sets the visual size of the input. Accepts `'sm'`, `'lg'`, or undefined.
*/
size: {
type: String as () => 'sm' | 'lg' | undefined,
default: undefined,
},
/**
* Helper or hint text displayed below the input.
*/
text: String,
/**
* Enables tooltip-style validation feedback messages.
*/
tooltipFeedback: Boolean,
/**
* Marks the input as valid.
*/
valid: Boolean,
/**
* Alternative to `modelValue`, mostly for manual `:value` binding.
*/
value: String,
},
emits: ['update:modelValue', 'change'],
setup(props, { emit, attrs }) {
const { delay, showPassword, size, invalid, valid } = toRefs(props)
const localValue = ref(props.modelValue ?? props.value ?? '')
const visible = ref(showPassword.value ?? false)
const inputType = computed(() => (visible.value ? 'text' : 'password'))
watch(
() => props.modelValue ?? props.value,
(val) => {
if (val !== localValue.value) {
localValue.value = val as string
}
}
)
let timeout: ReturnType<typeof setTimeout>
watch(localValue, (val) => {
if (delay.value) {
clearTimeout(timeout)
timeout = setTimeout(
() => {
emit('update:modelValue', val)
emit('change', val)
},
typeof delay.value === 'number' ? delay.value : 500
)
} else {
emit('update:modelValue', val)
emit('change', val)
}
})
const togglePassword = () => {
visible.value = !visible.value
}
return () =>
h(
CFormControlWrapper,
{
describedby: attrs['aria-describedby'] as string,
feedback: props.feedback,
feedbackInvalid: props.feedbackInvalid,
feedbackValid: props.feedbackValid,
floatingClassName: props.floatingLabel
? ['form-password', props.floatingClassName].join(' ')
: props.floatingClassName,
floatingLabel: props.floatingLabel,
id: props.id,
invalid: props.invalid,
label: props.label,
text: props.text,
tooltipFeedback: props.tooltipFeedback,
valid: props.valid,
},
{
default: () => {
const inputEl = h('input', {
...attrs,
id: props.id,
type: inputType.value,
class: [
'form-control',
{
[`form-control-${size.value}`]: size.value,
'is-invalid': invalid.value,
'is-valid': valid.value,
},
attrs.class,
],
value: localValue.value,
onInput: (e: Event) => {
localValue.value = (e.target as HTMLInputElement).value
},
disabled: props.disabled,
readOnly: props.readOnly,
})
const buttonEl = h(
'button',
{
type: 'button',
class: 'form-password-action',
'data-coreui-toggle': 'password',
'aria-label': props.ariaLabelToggler,
onClick: togglePassword,
},
[h('span', { class: 'form-password-action-icon' })]
)
const content = [inputEl, buttonEl]
return props.floatingLabel ? content : h('div', { class: 'form-password' }, content)
},
}
)
},
})