Spaces:
Sleeping
Sleeping
| <template> | |
| <button | |
| :class="buttonClasses" | |
| :disabled="disabled || loading" | |
| @click="handleClick" | |
| :type="type" | |
| > | |
| <span v-if="loading" class="saap-button__spinner"> | |
| <svg class="animate-spin -ml-1 mr-3 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> | |
| <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> | |
| <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> | |
| </svg> | |
| </span> | |
| <span v-if="icon && !loading" :class="iconClasses"> | |
| <component :is="icon" /> | |
| </span> | |
| <span class="saap-button__text"> | |
| <slot>{{ label }}</slot> | |
| </span> | |
| </button> | |
| </template> | |
| <script> | |
| export default { | |
| name: 'SaapButton', | |
| props: { | |
| variant: { | |
| type: String, | |
| default: 'primary', | |
| validator: (value) => ['primary', 'secondary', 'tertiary', 'danger', 'success'].includes(value) | |
| }, | |
| size: { | |
| type: String, | |
| default: 'md', | |
| validator: (value) => ['sm', 'md', 'lg', 'xl'].includes(value) | |
| }, | |
| disabled: { | |
| type: Boolean, | |
| default: false | |
| }, | |
| loading: { | |
| type: Boolean, | |
| default: false | |
| }, | |
| icon: { | |
| type: [String, Object], | |
| default: null | |
| }, | |
| iconPosition: { | |
| type: String, | |
| default: 'left', | |
| validator: (value) => ['left', 'right'].includes(value) | |
| }, | |
| label: { | |
| type: String, | |
| default: '' | |
| }, | |
| type: { | |
| type: String, | |
| default: 'button', | |
| validator: (value) => ['button', 'submit', 'reset'].includes(value) | |
| }, | |
| fullWidth: { | |
| type: Boolean, | |
| default: false | |
| } | |
| }, | |
| emits: ['click'], | |
| computed: { | |
| buttonClasses() { | |
| return [ | |
| 'saap-button', | |
| `saap-button--${this.variant}`, | |
| `saap-button--${this.size}`, | |
| { | |
| 'saap-button--disabled': this.disabled, | |
| 'saap-button--loading': this.loading, | |
| 'saap-button--full-width': this.fullWidth, | |
| 'saap-button--icon-right': this.icon && this.iconPosition === 'right' | |
| } | |
| ]; | |
| }, | |
| iconClasses() { | |
| return [ | |
| 'saap-button__icon', | |
| { | |
| 'saap-button__icon--right': this.iconPosition === 'right' | |
| } | |
| ]; | |
| } | |
| }, | |
| methods: { | |
| handleClick(event) { | |
| if (!this.disabled && !this.loading) { | |
| this.$emit('click', event); | |
| } | |
| } | |
| } | |
| }; | |
| </script> | |
| <style scoped> | |
| /* SAAP Design System - Button Component */ | |
| .saap-button { | |
| /* Base styles */ | |
| @apply inline-flex items-center justify-center; | |
| @apply font-medium rounded-lg transition-all duration-200; | |
| @apply focus:outline-none focus:ring-2 focus:ring-offset-2; | |
| @apply disabled:opacity-50 disabled:cursor-not-allowed; | |
| /* Typography from Design System */ | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; | |
| line-height: 1.5; | |
| } | |
| /* Size Variants - 8pt Grid System */ | |
| .saap-button--sm { | |
| @apply px-3 py-1.5 text-sm; | |
| min-height: 32px; /* 4 * 8pt */ | |
| } | |
| .saap-button--md { | |
| @apply px-4 py-2 text-sm; | |
| min-height: 40px; /* 5 * 8pt */ | |
| } | |
| .saap-button--lg { | |
| @apply px-6 py-3 text-base; | |
| min-height: 48px; /* 6 * 8pt */ | |
| } | |
| .saap-button--xl { | |
| @apply px-8 py-4 text-lg; | |
| min-height: 56px; /* 7 * 8pt */ | |
| } | |
| /* Variant Styles - SAAP Design System Colors */ | |
| .saap-button--primary { | |
| background-color: #2563EB; /* Primary Blue */ | |
| border: 1px solid #2563EB; | |
| color: white; | |
| } | |
| .saap-button--primary:hover:not(:disabled) { | |
| background-color: #1D4ED8; | |
| border-color: #1D4ED8; | |
| box-shadow: 0 4px 6px -1px rgba(37, 99, 235, 0.1); | |
| } | |
| .saap-button--primary:focus { | |
| @apply ring-blue-500; | |
| } | |
| .saap-button--secondary { | |
| background-color: #16A34A; /* Secondary Green */ | |
| border: 1px solid #16A34A; | |
| color: white; | |
| } | |
| .saap-button--secondary:hover:not(:disabled) { | |
| background-color: #15803D; | |
| border-color: #15803D; | |
| box-shadow: 0 4px 6px -1px rgba(22, 163, 74, 0.1); | |
| } | |
| .saap-button--secondary:focus { | |
| @apply ring-green-500; | |
| } | |
| .saap-button--tertiary { | |
| background-color: transparent; | |
| border: 1px solid #D1D5DB; | |
| color: #374151; | |
| } | |
| .saap-button--tertiary:hover:not(:disabled) { | |
| background-color: #F9FAFB; | |
| border-color: #9CA3AF; | |
| } | |
| .saap-button--tertiary:focus { | |
| @apply ring-gray-500; | |
| } | |
| .saap-button--danger { | |
| background-color: #DC2626; | |
| border: 1px solid #DC2626; | |
| color: white; | |
| } | |
| .saap-button--danger:hover:not(:disabled) { | |
| background-color: #B91C1C; | |
| border-color: #B91C1C; | |
| } | |
| .saap-button--danger:focus { | |
| @apply ring-red-500; | |
| } | |
| .saap-button--success { | |
| background-color: #16A34A; | |
| border: 1px solid #16A34A; | |
| color: white; | |
| } | |
| .saap-button--success:hover:not(:disabled) { | |
| background-color: #15803D; | |
| border-color: #15803D; | |
| } | |
| /* State Modifiers */ | |
| .saap-button--loading { | |
| cursor: wait; | |
| } | |
| .saap-button--full-width { | |
| @apply w-full; | |
| } | |
| /* Icon Styling */ | |
| .saap-button__icon { | |
| @apply w-5 h-5 flex-shrink-0; | |
| } | |
| .saap-button__icon:not(.saap-button__icon--right) { | |
| @apply mr-2; | |
| } | |
| .saap-button__icon--right { | |
| @apply ml-2 order-2; | |
| } | |
| .saap-button--icon-right .saap-button__text { | |
| @apply order-1; | |
| } | |
| /* Spinner */ | |
| .saap-button__spinner { | |
| @apply flex items-center; | |
| } | |
| /* Accessibility */ | |
| @media (prefers-reduced-motion: reduce) { | |
| .saap-button { | |
| transition: none; | |
| } | |
| } | |
| /* Dark mode support */ | |
| @media (prefers-color-scheme: dark) { | |
| .saap-button--tertiary { | |
| background-color: transparent; | |
| border-color: #4B5563; | |
| color: #D1D5DB; | |
| } | |
| .saap-button--tertiary:hover:not(:disabled) { | |
| background-color: #111827; | |
| border-color: #6B7280; | |
| } | |
| } | |
| </style> |