Skip to content

Commit

Permalink
feat(components): loading (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuagraber committed Jun 7, 2024
1 parent 043c474 commit ba9f960
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"recommendations": [
"tailwind.tailwindcss",
"vue.volar"
"Vue.volar"
]
}
78 changes: 78 additions & 0 deletions src/components/Spinner/PdapSpinner.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template>
<div class="pdap-spinner">
<Transition appear>
<svg
v-if="show"
:width="size"
:height="size"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
opacity=".25"
:stroke="color"
:fill="color"
/>
<path
d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z"
class="pdap-spinner-innards"
:stroke="color"
:fill="color"
/>
</svg>
</Transition>

<Transition :key="text" appear mode="out-in">
<p v-if="text && show" aria-live="polite">
{{ text }}
</p>
</Transition>
</div>
</template>

<script setup lang="ts">
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Transition } from 'vue';
import { PdapSpinnerProps } from './types';
withDefaults(defineProps<PdapSpinnerProps>(), {
color: 'currentColor',
size: 24,
text: '',
show: false,
});
</script>

<style>
@tailwind components;
@layer components {
.pdap-spinner {
@apply items-center bg-inherit flex flex-col gap-4 h-auto justify-center w-auto z-30;
}
.pdap-spinner-innards {
transform-origin: center;
animation: spinner 0.85s infinite linear;
}
}
@keyframes spinner {
100% {
transform: rotate(360deg);
}
}
</style>

<style scoped>
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease-in;
}
.v-enter-from,
.v-leave-to {
@apply opacity-0;
}
</style>
54 changes: 54 additions & 0 deletions src/components/Spinner/__snapshots__/spinner.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`PdapSpinner > applies custom color and size 1`] = `
<div class="pdap-spinner">
<transition-stub appear="true" css="true" persisted="false">
<svg height="48" viewBox="0 0 24 24" width="48" xmlns="http://www.w3.org/2000/svg">
<path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" fill="red" opacity=".25" stroke="red" />
<path class="pdap-spinner-innards" d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z" fill="red" stroke="red" />
</svg>
</transition-stub>
<transition-stub appear="true" css="true" mode="out-in" persisted="false">
<!--v-if-->
</transition-stub>
</div>
`;

exports[`PdapSpinner > does not render spinner when show prop is false 1`] = `
<div class="pdap-spinner">
<transition-stub appear="true" css="true" persisted="false">
<!--v-if-->
</transition-stub>
<transition-stub appear="true" css="true" mode="out-in" persisted="false">
<!--v-if-->
</transition-stub>
</div>
`;

exports[`PdapSpinner > renders spinner when show prop is true 1`] = `
<div class="pdap-spinner">
<transition-stub appear="true" css="true" persisted="false">
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" fill="currentColor" opacity=".25" stroke="currentColor" />
<path class="pdap-spinner-innards" d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z" fill="currentColor" stroke="currentColor" />
</svg>
</transition-stub>
<transition-stub appear="true" css="true" mode="out-in" persisted="false">
<!--v-if-->
</transition-stub>
</div>
`;

exports[`PdapSpinner > renders text when text prop is provided 1`] = `
<div class="pdap-spinner">
<transition-stub appear="true" css="true" persisted="false">
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" fill="currentColor" opacity=".25" stroke="currentColor" />
<path class="pdap-spinner-innards" d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z" fill="currentColor" stroke="currentColor" />
</svg>
</transition-stub>
<transition-stub appear="true" css="true" mode="out-in" persisted="false">
<p aria-live="polite">Loading...</p>
</transition-stub>
</div>
`;
1 change: 1 addition & 0 deletions src/components/Spinner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Spinner } from './PdapSpinner.vue';
60 changes: 60 additions & 0 deletions src/components/Spinner/spinner.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { shallowMount } from '@vue/test-utils';
import PdapSpinner from './PdapSpinner.vue';

import { describe, expect, it } from 'vitest';

describe('PdapSpinner', () => {
it('renders spinner when show prop is true', () => {
const wrapper = shallowMount(PdapSpinner, {
props: {
show: true,
},
});

expect(wrapper.find('svg').exists()).toBe(true);
expect(wrapper.html()).toMatchSnapshot();
});

it('does not render spinner when show prop is false', () => {
const wrapper = shallowMount(PdapSpinner, {
props: {
show: false,
},
});

expect(wrapper.find('svg').exists()).toBe(false);
expect(wrapper.html()).toMatchSnapshot();
});

it('renders text when text prop is provided', () => {
const text = 'Loading...';
const wrapper = shallowMount(PdapSpinner, {
props: {
show: true,
text,
},
});

expect(wrapper.text()).toContain(text);
expect(wrapper.html()).toMatchSnapshot();
});

it('applies custom color and size', () => {
const color = 'red';
const size = 48;
const wrapper = shallowMount(PdapSpinner, {
props: {
show: true,
color,
size,
},
});
const svg = wrapper.find('svg');
expect(svg.attributes('width')).toBe(`${size}`);
expect(svg.attributes('height')).toBe(`${size}`);
expect(wrapper.find('path').attributes('stroke')).toBe(color);
expect(wrapper.find('path').attributes('fill')).toBe(color);

expect(wrapper.html()).toMatchSnapshot();
});
});
6 changes: 6 additions & 0 deletions src/components/Spinner/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface PdapSpinnerProps {
color?: string;
size?: number;
text?: string;
show: boolean;
}
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export { QuickSearchForm } from './QuickSearchForm';
export { TileIcon } from './TileIcon';
export { Dropdown } from './Dropdown';
export { Breadcrumbs } from './Breadcrumbs';
export { Spinner } from './Spinner';
Loading

0 comments on commit ba9f960

Please sign in to comment.