feat: button component support loading state

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/581/head
Ryan Wang 2022-04-20 17:58:50 +08:00
parent 673d8c32a3
commit 3222f3449f
5 changed files with 132 additions and 15 deletions

View File

@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"prepare": "husky install",
"dev": "vite",
"dev": "vite --host",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview --port 5050",
"test:unit": "vitest --environment jsdom --run",

View File

@ -5,7 +5,33 @@
:disabled="disabled"
@click="handleClick"
>
<slot />
<span v-if="$slots.icon || loading" class="btn-icon self-center mr-3">
<svg
v-if="loading"
class="animate-spin h-5 w-5 text-white"
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>
<slot v-else name="icon" />
</span>
<span class="btn-content self-center">
<slot />
</span>
</button>
</template>
<script lang="ts" setup>
@ -48,6 +74,7 @@ const classes = computed(() => {
`btn-${props.type}`,
{ "btn-circle": props.circle },
{ "btn-block": props.block },
{ "btn-loading": props.loading },
];
});
@ -74,6 +101,8 @@ function handleClick() {
@apply px-4;
@apply outline-0;
@apply border-none;
@apply appearance-none;
@apply align-middle;
&:hover {
@apply opacity-90;
@ -106,7 +135,13 @@ function handleClick() {
.btn-block {
@apply w-full;
@apply block;
}
.btn-loading {
@apply cursor-not-allowed;
&:hover {
@apply opacity-100;
}
}
.btn-lg {

View File

@ -1,21 +1,61 @@
// Vitest Snapshot v1
exports[`Button > should render 1`] = `"<button class=\\"btn btn-md btn-default\\"></button>"`;
exports[`Button > should render 1`] = `
"<button class=\\"btn btn-md btn-default\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with block prop 1`] = `"<button class=\\"btn btn-md btn-default btn-block\\"></button>"`;
exports[`Button > should work with block prop 1`] = `
"<button class=\\"btn btn-md btn-default btn-block\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with circle prop 1`] = `"<button class=\\"btn btn-md btn-default btn-circle\\"></button>"`;
exports[`Button > should work with circle prop 1`] = `
"<button class=\\"btn btn-md btn-default btn-circle\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with disabled prop 1`] = `"<button class=\\"btn btn-md btn-default\\" disabled=\\"\\"></button>"`;
exports[`Button > should work with disabled prop 1`] = `
"<button class=\\"btn btn-md btn-default\\" disabled=\\"\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with size prop 1`] = `"<button class=\\"btn btn-lg btn-default\\"></button>"`;
exports[`Button > should work with size prop 1`] = `
"<button class=\\"btn btn-lg btn-default\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with size prop 2`] = `"<button class=\\"btn btn-sm btn-default\\"></button>"`;
exports[`Button > should work with size prop 2`] = `
"<button class=\\"btn btn-sm btn-default\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with size prop 3`] = `"<button class=\\"btn btn-xs btn-default\\"></button>"`;
exports[`Button > should work with size prop 3`] = `
"<button class=\\"btn btn-xs btn-default\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with type prop 1`] = `"<button class=\\"btn btn-md btn-primary\\"></button>"`;
exports[`Button > should work with type prop 1`] = `
"<button class=\\"btn btn-md btn-primary\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with type prop 2`] = `"<button class=\\"btn btn-md btn-secondary\\"></button>"`;
exports[`Button > should work with type prop 2`] = `
"<button class=\\"btn btn-md btn-secondary\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;
exports[`Button > should work with type prop 3`] = `"<button class=\\"btn btn-md btn-danger\\"></button>"`;
exports[`Button > should work with type prop 3`] = `
"<button class=\\"btn btn-md btn-danger\\">
<!--v-if--><span class=\\"btn-content self-center\\"></span>
</button>"
`;

View File

@ -1,7 +1,7 @@
<template>
<div class="flex h-full">
<aside class="navbar h-full" style="background: #fff">
<div class="logo flex justify-center py-6">
<div class="logo flex justify-center py-6 animate-pulse">
<img :src="logo" style="width: 80px" alt="Halo Logo" />
</div>
<VRoutesMenu :menus="menus" />

View File

@ -12,7 +12,7 @@
</div>
<h2 class="mb-1">Size:</h2>
<div class="mb-3">
<VButton class="mr-2" size="lg" type="secondary"> Large</VButton>
<VButton class="mr-2" size="lg" type="secondary">Large</VButton>
<VButton class="mr-2" type="secondary"> Default</VButton>
<VButton class="mr-2" size="sm" type="secondary"> sm</VButton>
<VButton size="xs" type="secondary"> xs</VButton>
@ -36,6 +36,46 @@
<VButton class="mr-2" disabled type="secondary"> Secondary</VButton>
<VButton disabled type="danger"> Danger</VButton>
</div>
<h2 class="mb-1">Loading:</h2>
<div class="mb-3">
<VButton class="mr-2" type="primary" :loading="buttonLoading">
Primary
</VButton>
<VButton class="mr-2" type="secondary" :loading="buttonLoading">
Secondary
</VButton>
<VButton class="mr-2" type="danger" :loading="buttonLoading">
Danger
</VButton>
<VButton type="default" :loading="buttonLoading"> Default </VButton>
</div>
<h2 class="mb-1">Icon:</h2>
<div class="mb-3">
<VButton class="mr-2" size="lg" type="secondary">
<template #icon>
<IconSettings />
</template>
Large
</VButton>
<VButton class="mr-2" type="secondary">
<template #icon>
<IconSettings />
</template>
Default
</VButton>
<VButton class="mr-2" size="sm" type="secondary">
<template #icon>
<IconSettings />
</template>
sm
</VButton>
<VButton size="xs" type="secondary">
<template #icon>
<IconSettings />
</template>
xs
</VButton>
</div>
</section>
<section class="box border-2 rounded p-2 mb-3">
<h1 class="text-xl font-bold mb-2">Input</h1>
@ -158,6 +198,7 @@
</template>
<script lang="ts" setup>
import { IconSettings } from "@/core/icons";
import { FilledLayout } from "../layouts";
import { VButton } from "@/components/base/button";
import { VInput } from "@/components/base/input";
@ -167,6 +208,7 @@ import { VRadio, VRadioGroup } from "@/components/base/radio";
import { VCheckbox, VCheckboxGroup } from "@/components/base/checkbox";
import { ref } from "vue";
const buttonLoading = ref(true);
const inputValue = ref();
const selectValue = ref();
const radioValue = ref("apple");