Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 1x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 5x 1x 1x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | <template> <template v-if="!props.buttonsConfig?.length"> <button :type="props.type || 'button'" :class="buttonClasses" :disabled="props.disabled" :aria-label="computedAriaLabel ?? ''" v-bind="restAttrs" @click="props.handleClick" > <slot> <template v-if="(props?.name ?? '').length > 0"> {{ $t(props.name || '') }} </template> </slot> </button> </template> <template v-else> <div :class="props.configCustomClass ?? 'flex gap-8'"> <button v-for="(btn, i) in props.buttonsConfig" :key="btn.id || btn.name || `btn-${i}`" :type="btn.type || 'button'" :class="getButtonClasses(btn)" :disabled="btn.disabled ?? false" :aria-label="getAriaLabel(btn)" v-bind="getRestAttrs(btn)" @click="btn.handleClick" > <template v-if="btn.name"> {{ $t(btn.name) }} </template> <template v-else-if="btn.children"> <component :is="btn.children" /> </template> </button> </div> </template> </template> <script setup lang="ts"> import { isValidAttribute } from '@/shared/utils/safeAttributes'; import { clsx } from 'clsx'; import { computed, useAttrs } from 'vue'; import { useI18n } from 'vue-i18n'; import type { IButtonComponent } from './Button.model'; const props = defineProps<IButtonComponent>(); const restAttrs = useAttrs(); const { t } = useI18n(); const computedAriaLabelFallback = computed(() => ((props.name ?? '').length > 0 ? t(props.name || '') : 'Unnamed Button')); const computedAriaLabel = computed(() => { const hasLabelledBy = 'aria-labelledby' in restAttrs && !!restAttrs['aria-labelledby']; return !hasLabelledBy ? String(restAttrs['aria-label'] ?? computedAriaLabelFallback.value) : ''; }); const getButtonClasses = (btn: IButtonComponent) => { const variantClasses = { primary: 'primary', secondary: 'secondary', tertiary: 'tertiary', round: 'round rounded-full', }; const sizeClasses = { xs: btn.variant === 'round' ? 'text-sm h-6 w-6' : 'text-xs px-1 py-1', sm: btn.variant === 'round' ? 'text-base h-8 w-8' : 'text-sm px-3 py-2', lg: btn.variant === 'round' ? 'text-xl h-12 w-12' : 'text-base px-4 py-3', }; return clsx([ 'button-component', variantClasses[btn.variant || 'primary'], sizeClasses[btn.size || 'sm'], btn.disabled ? 'bg-gray text-disabled cursor-not-allowed' : '', typeof btn.className === 'string' ? btn.className : clsx(btn.className), { active: btn.active }, ]); }; const buttonClasses = computed(() => getButtonClasses(props)); const getAriaLabel = (btn: IButtonComponent) => { const hasLabelledBy = 'aria-labelledby' in btn && !!btn['aria-labelledby']; return !hasLabelledBy ? (btn['aria-label'] ?? (btn.name ? t(btn.name) : 'Unnamed Button')) : undefined; }; const getRestAttrs = (btn: IButtonComponent) => { const { id, key, name, type, handleClick, active, className, tooltip, variant, buttonsConfig, configCustomClass, size, selected, disabled, children, ...rest } = btn; const safeAttrs: Record<string, any> = {}; for (const [k, v] of Object.entries(rest)) { if (isValidAttribute(k)) { safeAttrs[k] = v; } } return safeAttrs; }; </script> |