feat: enhance Button component with new variants, sizes, and styles
parent
136543398d
commit
2cf758d770
|
@ -1,9 +1,56 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<a-button class="btn btn-primary">Primary Button</a-button>
|
||||
<a-button class="btn btn-secondary">Default Button</a-button>
|
||||
<a-button class="btn btn-error">Dashed Button</a-button>
|
||||
<a-button class="btn btn-link">Text Button</a-button>
|
||||
<a-button class="btn btn-link">Link Button</a-button>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<a-button variant="solid" size="lg">Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" disabled>Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" loading>Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" danger>Danger Solid Button</a-button>
|
||||
<a-button variant="solid" size="lg" danger disabled>Disabled Danger Solid Button</a-button>
|
||||
<br />
|
||||
<a-button variant="outlined" size="sm">Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="md">Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg">Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" disabled>Disabled Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" loading>Loading Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" danger>Danger Outlined Button</a-button>
|
||||
<a-button variant="outlined" size="lg" danger disabled>
|
||||
Disabled Danger Outlined Button
|
||||
</a-button>
|
||||
<br />
|
||||
<a-button variant="text" size="sm">Text Button</a-button>
|
||||
<a-button variant="text" size="md">Text Button</a-button>
|
||||
<a-button variant="text" size="lg">Text Button</a-button>
|
||||
<a-button variant="text" size="lg" disabled>Disabled Text Button</a-button>
|
||||
<a-button variant="text" size="lg" loading>Loading Text Button</a-button>
|
||||
<a-button variant="text" size="lg" danger>Danger Text Button</a-button>
|
||||
<a-button variant="text" size="lg" danger disabled>Disabled Danger Text Button</a-button>
|
||||
<br />
|
||||
<a-button variant="link" size="sm">Link Button</a-button>
|
||||
<a-button variant="link" size="md">Link Button</a-button>
|
||||
<a-button variant="link" size="lg">Link Button</a-button>
|
||||
<a-button variant="link" size="lg" disabled>Disabled Link Button</a-button>
|
||||
<a-button variant="link" size="lg" loading>Loading Link Button</a-button>
|
||||
<a-button variant="link" size="lg" danger>Danger Link Button</a-button>
|
||||
<a-button variant="link" size="lg" danger disabled>Disabled Danger Link Button</a-button>
|
||||
<br />
|
||||
<a-button variant="dashed" size="sm">Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="md">Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg">Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" disabled>Disabled Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" loading>Loading Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" danger>Danger Dashed Button</a-button>
|
||||
<a-button variant="dashed" size="lg" danger disabled>Disabled Danger Dashed Button</a-button>
|
||||
<br />
|
||||
<a-button variant="filled" size="sm">Filled Button</a-button>
|
||||
<a-button variant="filled" size="md">Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg">Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" disabled>Disabled Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" loading>Loading Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" danger>Danger Filled Button</a-button>
|
||||
<a-button variant="filled" size="lg" danger disabled>Disabled Danger Filled Button</a-button>
|
||||
|
||||
<a-button color="purple">Purple Button</a-button>
|
||||
<a-button color="blue">Blue Button</a-button>
|
||||
<a-button color="green">Green Button</a-button>
|
||||
<a-button color="red">Red Button</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
@import 'tailwindcss' source(none);
|
||||
@plugin '@tailwindcss/typography';
|
||||
|
||||
@utility text-tint-* {
|
||||
color: color-mix(in srgb, --value(--color-*, [*]), white calc(--modifier(integer) * 1%));
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
"license": "MIT",
|
||||
"main": "./dist/lib.cjs",
|
||||
"module": "./dist/lib.mjs",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"src/style",
|
||||
|
@ -72,6 +72,7 @@
|
|||
"@floating-ui/dom": "^1.6.13",
|
||||
"@floating-ui/vue": "^1.1.6",
|
||||
"lodash-es": "^4.17.21",
|
||||
"@ctrl/tinycolor": "^4.0.0",
|
||||
"resize-observer-polyfill": "^1.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<button class="ant-btn" :class="classes" @click="$emit('click', $event)">
|
||||
<button :class="rootClass" @click="$emit('click', $event)" :disabled="disabled" :style="cssVars">
|
||||
<slot name="loading"></slot>
|
||||
<slot name="icon"></slot>
|
||||
<slot></slot>
|
||||
</button>
|
||||
</template>
|
||||
|
@ -7,20 +9,42 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { buttonProps, buttonEmits, ButtonSlots } from './meta'
|
||||
import { getCssVarColor } from '@/utils/colorAlgorithm'
|
||||
|
||||
const props = defineProps(buttonProps)
|
||||
|
||||
defineEmits(buttonEmits)
|
||||
defineSlots<ButtonSlots>()
|
||||
|
||||
const classes = computed(() => {
|
||||
return [
|
||||
'rounded-md px-4 py-2 cursor-pointer',
|
||||
props.type,
|
||||
{
|
||||
'bg-primary text-primary-content': props.type === 'primary',
|
||||
'bg-secondary text-secondary-content': props.type === 'secondary',
|
||||
},
|
||||
]
|
||||
// todo: color value should from theme provider
|
||||
const color = computed(() => {
|
||||
if (props.disabled) {
|
||||
return 'rgba(0,0,0,0.25)'
|
||||
}
|
||||
if (props.color) {
|
||||
return props.color
|
||||
}
|
||||
if (props.danger) {
|
||||
return '#ff4d4f'
|
||||
}
|
||||
if (props.variant === 'text') {
|
||||
return '#000000'
|
||||
}
|
||||
|
||||
return '#1677ff'
|
||||
})
|
||||
|
||||
const rootClass = computed(() => {
|
||||
return {
|
||||
'ant-btn': true,
|
||||
[`ant-btn-${props.variant}`]: true,
|
||||
[`ant-btn-${props.size}`]: true,
|
||||
'ant-btn-danger': props.danger,
|
||||
'ant-btn-loading': props.loading,
|
||||
'ant-btn-disabled': props.disabled,
|
||||
}
|
||||
})
|
||||
const cssVars = computed(() => {
|
||||
return getCssVarColor(color.value)
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -2,7 +2,6 @@ import { App, Plugin } from 'vue'
|
|||
import Button from './Button.vue'
|
||||
import './style/index.css'
|
||||
|
||||
// 导出组件
|
||||
export { default as Button } from './Button.vue'
|
||||
export * from './meta'
|
||||
|
||||
|
|
|
@ -6,9 +6,61 @@ export const buttonProps = {
|
|||
* Specifies the visual style variant of the button
|
||||
* @default 'primary'
|
||||
*/
|
||||
type: {
|
||||
type: String as PropType<'primary' | 'secondary'>,
|
||||
default: 'primary',
|
||||
variant: {
|
||||
type: String as PropType<'solid' | 'outlined' | 'text' | 'link' | 'dashed' | 'filled'>,
|
||||
default: 'solid',
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies the size of the button
|
||||
* @default 'md'
|
||||
*/
|
||||
size: {
|
||||
type: String as PropType<'sm' | 'md' | 'lg'>,
|
||||
default: 'md',
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies the shape of the button
|
||||
* @default 'default'
|
||||
*/
|
||||
shape: {
|
||||
type: String as PropType<'default' | 'circle' | 'round'>,
|
||||
default: 'default',
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies the loading state of the button
|
||||
* @default false
|
||||
*/
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies the disabled state of the button
|
||||
* @default false
|
||||
*/
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies the danger state of the button
|
||||
* @default false
|
||||
*/
|
||||
danger: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies the color of the button
|
||||
*/
|
||||
color: {
|
||||
type: String,
|
||||
},
|
||||
} as const
|
||||
|
||||
|
@ -31,6 +83,14 @@ export const buttonSlots = {
|
|||
* Main content slot for the button text or custom content
|
||||
*/
|
||||
default: (_: any) => null as any,
|
||||
/**
|
||||
* Slot for the button icon
|
||||
*/
|
||||
icon: (_: any) => null as any,
|
||||
/**
|
||||
* Slot for the button loading indicator
|
||||
*/
|
||||
loading: (_: any) => null as any,
|
||||
} as const
|
||||
|
||||
export type ButtonSlots = typeof buttonSlots
|
||||
|
|
|
@ -1,5 +1,50 @@
|
|||
@reference '../../../style/tailwind.css';
|
||||
|
||||
.ant-btn {
|
||||
@apply text-primary-content;
|
||||
@apply relative;
|
||||
@apply inline-flex shrink-0 cursor-pointer items-center justify-center gap-1 whitespace-nowrap;
|
||||
@apply border-1 text-sm;
|
||||
@apply box-border rounded-md px-4 transition-all duration-200 select-none;
|
||||
&:where(.ant-btn-disabled) {
|
||||
@apply cursor-not-allowed;
|
||||
}
|
||||
&:where(.ant-btn-loading) {
|
||||
@apply cursor-default opacity-50;
|
||||
}
|
||||
|
||||
&:where(.ant-btn-solid) {
|
||||
@apply border-none bg-[var(--bg-color)] text-[var(--bg-color-content)];
|
||||
@apply not-disabled:hover:bg-[var(--bg-color-hover)] not-disabled:active:bg-[var(--bg-color-active)];
|
||||
}
|
||||
&:where(.ant-btn-outlined),
|
||||
&:where(.ant-btn-dashed) {
|
||||
@apply border-[var(--border-color-tint-30)] bg-transparent text-[var(--text-color)];
|
||||
@apply not-disabled:hover:border-[var(--border-color-hover)] not-disabled:hover:text-[var(--text-color-hover)] not-disabled:active:border-[var(--border-color-active)] not-disabled:active:text-[var(--text-color-active)];
|
||||
@apply disabled:border-[var(--border-color-tint-80)];
|
||||
}
|
||||
&:where(.ant-btn-text) {
|
||||
@apply border-none bg-transparent text-[var(--text-color)];
|
||||
@apply not-disabled:hover:bg-[var(--bg-color-tint-90)] not-disabled:hover:text-[var(--text-color-hover)];
|
||||
}
|
||||
|
||||
&:where(.ant-btn-link) {
|
||||
@apply border-none bg-transparent text-[var(--text-color)] not-disabled:hover:text-[var(--text-color-hover)];
|
||||
}
|
||||
&:where(.ant-btn-dashed) {
|
||||
@apply border-dashed;
|
||||
}
|
||||
&:where(.ant-btn-filled) {
|
||||
@apply border-none bg-[var(--bg-color-tint-90)] text-[var(--text-color)] not-disabled:hover:text-[var(--text-color-hover)];
|
||||
@apply not-disabled:hover:bg-[var(--bg-color-tint-80)] not-disabled:active:bg-[var(--bg-color-tint-80)];
|
||||
}
|
||||
|
||||
&:where(.ant-btn-sm) {
|
||||
@apply h-6 text-xs;
|
||||
}
|
||||
&:where(.ant-btn-md) {
|
||||
@apply h-8 text-sm;
|
||||
}
|
||||
&:where(.ant-btn-lg) {
|
||||
@apply h-10 text-base;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import { TinyColor } from '@ctrl/tinycolor'
|
||||
|
||||
export const getAlphaColor = (baseColor: string, alpha: number) =>
|
||||
new TinyColor(baseColor).setAlpha(alpha).toRgbString()
|
||||
|
||||
export const getSolidColor = (baseColor: string, brightness: number) => {
|
||||
const instance = new TinyColor(baseColor)
|
||||
return instance.darken(brightness).toHexString()
|
||||
}
|
||||
|
||||
export const getTintColor = (baseColor: string, tintNumber: number) => {
|
||||
return new TinyColor(baseColor).tint(tintNumber).toString()
|
||||
}
|
||||
|
||||
export const getShadeColor = (baseColor: string, shadeNumber: number) => {
|
||||
return new TinyColor(baseColor).shade(shadeNumber).toString()
|
||||
}
|
||||
|
||||
export const getCssVarColor = (baseColor: string) => {
|
||||
return {
|
||||
'--bg-color': baseColor,
|
||||
'--bg-color-hover': getTintColor(baseColor, 10),
|
||||
'--bg-color-active': getTintColor(baseColor, 20),
|
||||
'--bg-color-content': '#ffffff',
|
||||
'--border-color': baseColor,
|
||||
'--border-color-hover': getTintColor(baseColor, 10),
|
||||
'--border-color-active': getTintColor(baseColor, 20),
|
||||
'--border-color-tint-10': getTintColor(baseColor, 10),
|
||||
'--border-color-tint-20': getTintColor(baseColor, 20),
|
||||
'--border-color-tint-30': getTintColor(baseColor, 30),
|
||||
'--border-color-tint-40': getTintColor(baseColor, 40),
|
||||
'--border-color-tint-50': getTintColor(baseColor, 50),
|
||||
'--border-color-tint-60': getTintColor(baseColor, 60),
|
||||
'--border-color-tint-70': getTintColor(baseColor, 70),
|
||||
'--border-color-tint-80': getTintColor(baseColor, 80),
|
||||
'--border-color-tint-90': getTintColor(baseColor, 90),
|
||||
'--bg-color-tint-10': getTintColor(baseColor, 10),
|
||||
'--bg-color-tint-20': getTintColor(baseColor, 20),
|
||||
'--bg-color-tint-30': getTintColor(baseColor, 30),
|
||||
'--bg-color-tint-40': getTintColor(baseColor, 40),
|
||||
'--bg-color-tint-50': getTintColor(baseColor, 50),
|
||||
'--bg-color-tint-60': getTintColor(baseColor, 60),
|
||||
'--bg-color-tint-70': getTintColor(baseColor, 70),
|
||||
'--bg-color-tint-80': getTintColor(baseColor, 80),
|
||||
'--bg-color-tint-90': getTintColor(baseColor, 90),
|
||||
'--text-color': baseColor,
|
||||
'--text-color-hover': getTintColor(baseColor, 10),
|
||||
'--text-color-active': getTintColor(baseColor, 20),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue