initial
This commit is contained in:
145
layers/ui/components/button/index.vue
Normal file
145
layers/ui/components/button/index.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<Component
|
||||
:is="as"
|
||||
:class="[
|
||||
cn.b(),
|
||||
cn.m(type),
|
||||
cn.m(`${type}_${color}`),
|
||||
cn.m(size !== 'medium' ? size : ''),
|
||||
cn.is('one-icon-only', oneIconOnly),
|
||||
cn.has('icon', hasIcon),
|
||||
cn.is('disabled', disabled),
|
||||
cn.is('hover', state === 'hover'),
|
||||
cn.is('active', state === 'active'),
|
||||
]"
|
||||
:disabled="disabled"
|
||||
v-bind="attributes"
|
||||
@click="handleClick"
|
||||
>
|
||||
<span
|
||||
v-if="hasLeftIcon && displayIcon"
|
||||
:class="[cn.e('icon'), cn.em('icon', 'left')]"
|
||||
>
|
||||
<slot name="left-icon">
|
||||
<Component :is="resolveComponent(`ui-icon-${leftIcon}`)" />
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="!iconOnly"
|
||||
:class="[cn.e('content')]"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="hasRightIcon && displayIcon"
|
||||
:class="[cn.e('icon'), cn.em('icon', 'right')]"
|
||||
>
|
||||
<slot name="right-icon">
|
||||
<Component :is="resolveComponent(`ui-icon-${rightIcon}`)" />
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="loading && !disabled"
|
||||
:class="[cn.e('loader')]"
|
||||
>
|
||||
<slot name="loader">
|
||||
<UiSpinner
|
||||
:delay="typeof loading === 'number' ? loading : undefined"
|
||||
@done="$emit('update:loading', false)"
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
</Component>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ButtonHTMLAttributes } from 'vue'
|
||||
import type { UiIcon } from '#build/types/ui/icons'
|
||||
|
||||
export interface Props {
|
||||
type?: 'filled' | 'outlined' | 'ghost' | 'link'
|
||||
color?: 'primary' | 'secondary'
|
||||
size?: 'small' | 'medium' | 'large'
|
||||
nativeType?: ButtonHTMLAttributes['type']
|
||||
icon?: UiIcon
|
||||
leftIcon?: UiIcon
|
||||
rightIcon?: UiIcon
|
||||
disabled?: boolean
|
||||
loading?: boolean | number
|
||||
state?: 'hover' | 'active'
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'UiButton',
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'filled',
|
||||
color: 'primary',
|
||||
size: 'medium',
|
||||
nativeType: 'button',
|
||||
disabled: false,
|
||||
loading: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [e: Event]
|
||||
'update:loading': []
|
||||
}>()
|
||||
|
||||
const slots = useSlots()
|
||||
const attrs = useAttrs()
|
||||
|
||||
const linkComponent = useGlobalConfig('LINK_COMPONENT', 'a')
|
||||
|
||||
const cn = useClassname('ui-button')
|
||||
|
||||
const as = computed(() => (attrs.href ? linkComponent.value : 'button'))
|
||||
const attributes = computed(() => {
|
||||
if (as.value === 'button') {
|
||||
return {
|
||||
type: props.nativeType,
|
||||
...attrs,
|
||||
}
|
||||
}
|
||||
|
||||
return attrs
|
||||
})
|
||||
|
||||
const leftIcon = computed(() => props.leftIcon ?? props.icon)
|
||||
|
||||
const hasLeftIcon = computed(() => !!leftIcon.value || !!slots.leftIcon)
|
||||
const hasRightIcon = computed(() => !!props.rightIcon || !!slots.rightIcon)
|
||||
const hasIcon = computed(() => hasLeftIcon.value || hasRightIcon.value)
|
||||
const oneIconOnly = computed(
|
||||
() =>
|
||||
((hasLeftIcon.value && !hasRightIcon.value)
|
||||
|| (!hasLeftIcon.value && hasRightIcon.value))
|
||||
&& !slots.default,
|
||||
)
|
||||
|
||||
const iconOnly = computed(
|
||||
() => (hasIcon.value || props.loading) && !slots.default,
|
||||
)
|
||||
|
||||
const displayIcon = computed(
|
||||
() => hasIcon.value && ((props.loading && props.disabled) || !props.loading),
|
||||
)
|
||||
|
||||
function handleClick(event: Event) {
|
||||
if (props.disabled || props.loading) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
else {
|
||||
emit('click', event)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use 'styles';
|
||||
</style>
|
||||
Reference in New Issue
Block a user