import { ref, Slot, watch, computed, Teleport, PropType, Transition, TeleportProps, defineComponent, } from 'vue'; // Utils import { truthProp, getZIndexStyle, stopPropagation, createNamespace, } from '../utils'; // Composables import { useClickAway } from '@vant/use'; // Components import NumberKeyboardKey, { KeyType } from './NumberKeyboardKey'; const [name, bem] = createNamespace('number-keyboard'); export type NumberKeyboardTheme = 'default' | 'custom'; type KeyConfig = { text?: number | string; type?: KeyType; color?: string; wider?: boolean; }; export default defineComponent({ name, props: { show: Boolean, title: String, zIndex: [Number, String], teleport: [String, Object] as PropType, transition: truthProp, blurOnClose: truthProp, showDeleteKey: truthProp, randomKeyOrder: Boolean, closeButtonText: String, deleteButtonText: String, closeButtonLoading: Boolean, hideOnClickOutside: truthProp, safeAreaInsetBottom: truthProp, theme: { type: String as PropType, default: 'default', }, modelValue: { type: String, default: '', }, extraKey: { type: [String, Array] as PropType, default: '', }, maxlength: { type: [Number, String], default: Number.MAX_VALUE, }, }, emits: [ 'show', 'hide', 'blur', 'input', 'close', 'delete', 'update:modelValue', ], setup(props, { emit, slots }) { const root = ref(); const genBasicKeys = () => { const keys: KeyConfig[] = Array(9) .fill('') .map((_, i) => ({ text: i + 1 })); if (props.randomKeyOrder) { keys.sort(() => (Math.random() > 0.5 ? 1 : -1)); } return keys; }; const genDefaultKeys = (): KeyConfig[] => [ ...genBasicKeys(), { text: props.extraKey as string, type: 'extra' }, { text: 0 }, { text: props.showDeleteKey ? props.deleteButtonText : '', type: props.showDeleteKey ? 'delete' : '', }, ]; const genCustomKeys = () => { const keys = genBasicKeys(); const { extraKey } = props; const extraKeys = Array.isArray(extraKey) ? extraKey : [extraKey]; if (extraKeys.length === 1) { keys.push( { text: 0, wider: true }, { text: extraKeys[0], type: 'extra' } ); } else if (extraKeys.length === 2) { keys.push( { text: extraKeys[0], type: 'extra' }, { text: 0 }, { text: extraKeys[1], type: 'extra' } ); } return keys; }; const keys = computed(() => props.theme === 'custom' ? genCustomKeys() : genDefaultKeys() ); const onBlur = () => { if (props.show) { emit('blur'); } }; const onClose = () => { emit('close'); if (props.blurOnClose) { onBlur(); } }; const onAnimationEnd = () => emit(props.show ? 'show' : 'hide'); const onPress = (text: string, type: KeyType) => { if (text === '') { if (type === 'extra') { onBlur(); } return; } const value = props.modelValue; if (type === 'delete') { emit('delete'); emit('update:modelValue', value.slice(0, value.length - 1)); } else if (type === 'close') { onClose(); } else if (value.length < props.maxlength) { emit('input', text); emit('update:modelValue', value + text); } }; const renderTitle = () => { const { title, theme, closeButtonText } = props; const leftSlot = slots['title-left']; const showClose = closeButtonText && theme === 'default'; const showTitle = title || showClose || leftSlot; if (!showTitle) { return; } return (
{leftSlot && {leftSlot()}} {title &&

{title}

} {showClose && ( )}
); }; const renderKeys = () => { return keys.value.map((key) => { const keySlots: Record = {}; if (key.type === 'delete') { keySlots.default = slots.delete; } if (key.type === 'extra') { keySlots.default = slots['extra-key']; } return ( ); }); }; const renderSidebar = () => { if (props.theme === 'custom') { return (
{props.showDeleteKey && ( )}
); } }; watch( () => props.show, (value) => { if (!props.transition) { emit(value ? 'show' : 'hide'); } } ); if (props.hideOnClickOutside) { useClickAway(root, onClose, { eventName: 'touchstart' }); } return () => { const Title = renderTitle(); const Content = (
{Title}
{renderKeys()}
{renderSidebar()}
); if (props.teleport) { return {Content}; } return Content; }; }, });