Merge branch 'alert' into 'main'
Alert See merge request cellule-financiere-pmo/design-system/visua-vue!11
This commit is contained in:
commit
06e61bd809
|
@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.11] - 2025-07-27
|
||||
### Added
|
||||
- Alert compoenent
|
||||
- useAlert composable
|
||||
|
||||
## [1.0.10] - 2025-07-27
|
||||
### Added
|
||||
- File compoenent
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# visua-vue
|
||||
|
||||
**Current version: v1.0.10**
|
||||
**Current version: v1.0.11**
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@cellule-financiere-pmo/visua-vue",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@cellule-financiere-pmo/visua-vue",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@cellule-financiere-pmo/visua": "1.1.3",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@cellule-financiere-pmo/visua-vue",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
// import VSelectView from '../template/VSelectView.vue';
|
||||
// import VProgressBarView from '../template/VProgressBarView.vue';
|
||||
// import VMessageView from '../template/VMessageView.vue';
|
||||
import VFileUploadView from '../template/VFileUploadView.vue'
|
||||
// import VFileUploadView from '../template/VFileUploadView.vue';
|
||||
import VAlertView from '../template/VAlertView.vue';
|
||||
</script>
|
||||
|
||||
|
||||
|
@ -24,5 +25,6 @@ import VFileUploadView from '../template/VFileUploadView.vue'
|
|||
<VSelectView/> -->
|
||||
<!-- <VProgressBarView/> -->
|
||||
<!-- <VMessageView/> -->
|
||||
<VFileUploadView/>
|
||||
<!-- <VFileUploadView/> -->
|
||||
<VAlertView/>
|
||||
</template>
|
||||
|
|
|
@ -15,3 +15,4 @@
|
|||
@import './primevue-style/progressbar.css';
|
||||
@import './primevue-style/fileupload.css';
|
||||
@import './primevue-style/scrollpanel.css';
|
||||
@import './primevue-style/toast.css';
|
||||
|
|
37
src/assets/style/primevue-style/toast.css
Normal file
37
src/assets/style/primevue-style/toast.css
Normal file
|
@ -0,0 +1,37 @@
|
|||
:root{
|
||||
--p-toast-width: 25rem;
|
||||
--p-toast-border-radius: 0px;
|
||||
--p-toast-border-width: var(--large-border-width);
|
||||
--p-toast-icon-size: 1.5rem;
|
||||
--p-toast-content-padding: 0.25rem;
|
||||
--p-toast-content-gap: 0.5rem;
|
||||
--p-toast-text-gap: 0.5rem;
|
||||
--p-toast-summary-font-weight: var( --text-body-MD-standard-text-weight);
|
||||
--p-toast-summary-font-size: var(--text-body-MD-standard-text-size);
|
||||
--p-toast-detail-font-weight: var( --text-body-MD-standard-text-Regular-weight);
|
||||
--p-toast-detail-font-size: var(--text-body-MD-standard-text-Regular-size);
|
||||
/* info */
|
||||
--p-toast-info-background: var(--background-contrast-info);
|
||||
--p-toast-info-border-color: var(--border-plain-info);
|
||||
--p-toast-info-color: var(--text-default-info);
|
||||
--p-toast-info-detail-color: var(--input-color);
|
||||
--p-toast-info-shadow: var(--shadow);
|
||||
/* success */
|
||||
--p-toast-success-background: var(--background-contrast-success);
|
||||
--p-toast-success-border-color: var(--border-plain-success);
|
||||
--p-toast-success-color: var(--text-default-success);
|
||||
--p-toast-success-detail-color: var(--input-color);
|
||||
--p-toast-success-shadow: var(--shadow);
|
||||
/* warn */
|
||||
--p-toast-warn-background: var(--background-contrast-warning);
|
||||
--p-toast-warn-border-color: var(--border-plain-warning);
|
||||
--p-toast-warn-color: var(--text-default-warning);
|
||||
--p-toast-warn-detail-color: var(--input-color);
|
||||
--p-toast-warn-shadow: var(--shadow);
|
||||
/* error */
|
||||
--p-toast-error-background: var(--background-contrast-error);
|
||||
--p-toast-error-border-color: var(--border-plain-error);
|
||||
--p-toast-error-color: var(--text-default-error);
|
||||
--p-toast-error-detail-color: var(--input-color);
|
||||
--p-toast-error-shadow: var(--shadow);
|
||||
}
|
62
src/components/alert/IVAlert.type.ts
Normal file
62
src/components/alert/IVAlert.type.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Interface representing the properties of an Alert component.
|
||||
*/
|
||||
export default interface IVAlert {
|
||||
/**
|
||||
* Determines if the alert should be visible.
|
||||
* @default false
|
||||
*/
|
||||
alert?: boolean;
|
||||
|
||||
/**
|
||||
* Indicates whether the alert has been closed.
|
||||
* @default false
|
||||
*/
|
||||
closed?: boolean;
|
||||
|
||||
/**
|
||||
* Specifies if the alert can be closed by the user.
|
||||
* @default false
|
||||
*/
|
||||
closeable?: boolean;
|
||||
|
||||
/**
|
||||
* Unique identifier for the alert instance.
|
||||
*/
|
||||
id?: string;
|
||||
|
||||
/**
|
||||
* Title displayed at the top of the alert.
|
||||
*/
|
||||
title?: string;
|
||||
|
||||
/**
|
||||
* Detailed description or message content of the alert.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Determines if a smaller variant of the alert should be displayed.
|
||||
* @default false
|
||||
*/
|
||||
small?: boolean;
|
||||
|
||||
/**
|
||||
* Type of alert, affecting its visual style and icon.
|
||||
* - `"success"`: Indicates a successful or positive action.
|
||||
* - `"error"`: Indicates an error or critical issue.
|
||||
* - `"info"`: Provides general information.
|
||||
* - `"warn"`: Indicates a warning or potential issue.
|
||||
*/
|
||||
type?: "success" | "error" | "info" | "warn" | undefined;
|
||||
|
||||
/**
|
||||
* Label for the close button, useful for accessibility.
|
||||
*/
|
||||
closeButtonLabel?: string;
|
||||
|
||||
/**
|
||||
* Time in milliseconds after which the alert automatically disappears.
|
||||
*/
|
||||
lifeTime?: number;
|
||||
}
|
106
src/components/alert/VAlert.vue
Normal file
106
src/components/alert/VAlert.vue
Normal file
|
@ -0,0 +1,106 @@
|
|||
<script setup lang="ts">
|
||||
import Toast from 'primevue/toast';
|
||||
import VButton from '../button/VButton.vue';
|
||||
import type { ToastProps } from 'primevue/toast';
|
||||
import styles from '@visua/typography.module.css';
|
||||
|
||||
const props = withDefaults(defineProps<ToastProps>(), {
|
||||
group: undefined,
|
||||
position: 'bottom-center',
|
||||
breakpoints: undefined
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
'close',
|
||||
'life-end'
|
||||
]);
|
||||
|
||||
const getIconColor = (type?: string) => {
|
||||
switch (type) {
|
||||
case 'error': return 'var(--text-default-error)';
|
||||
case 'warn' : return 'var(--text-default-warning)';
|
||||
case 'success' : return 'var(--text-default-success)';
|
||||
case 'info': return 'var(--text-default-info)';
|
||||
default:
|
||||
return 'var(--text-default-success)';
|
||||
}
|
||||
};
|
||||
|
||||
const getIconClass = (type?: string) => {
|
||||
switch (type) {
|
||||
case 'error': return 'ri-spam-fill';
|
||||
case 'warn' : return 'ri-alert-fill';
|
||||
case 'success' : return 'ri-checkbox-circle-fill';
|
||||
case 'info': return 'ri-information-fill';
|
||||
default:
|
||||
return 'ri-information-fill';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Toast
|
||||
:position=props.position
|
||||
:group="props.group"
|
||||
:breakpoints="props.breakpoints"
|
||||
class="p-toast"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
aria-atomic="true"
|
||||
@close="emit('close', $event)"
|
||||
@life-end="emit('life-end', $event)"
|
||||
>
|
||||
<template #container="{message, closeCallback}">
|
||||
<div class="header">
|
||||
<i
|
||||
style="font-size: var(--p-message-icon-lg-size);"
|
||||
:class="getIconClass(message.severity)"
|
||||
:style="{color: getIconColor(message.severity)}"
|
||||
/>
|
||||
<span
|
||||
:class="[styles['text-body-MD-standard-text-Medium']]"
|
||||
:style="{color: getIconColor(message.severity)}"
|
||||
style="width: 100%;"
|
||||
>
|
||||
{{ message.summary }}
|
||||
</span>
|
||||
<VButton
|
||||
title="Fermer le message"
|
||||
tertiary
|
||||
no-outline
|
||||
size="sm"
|
||||
icon-only
|
||||
aria-label="Fermer"
|
||||
icon="ri-close-line"
|
||||
type="button"
|
||||
@click="closeCallback"
|
||||
style="height: 2rem;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="!!message.detail"
|
||||
:class="['content', styles['text-body-MD-standard-text-Regular']]"
|
||||
>
|
||||
<span>{{ message.detail }}</span>
|
||||
<slot name="footer"/>
|
||||
</div>
|
||||
</template>
|
||||
</Toast>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.header{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.25rem;
|
||||
padding: var(--p-toast-text-gap);
|
||||
color: var(--text-title-grey);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.content{
|
||||
padding: 0rem 0.825rem 0.5rem 0.825rem;
|
||||
color: var(--text-default-grey);
|
||||
}
|
||||
</style>
|
24
src/components/composable/useAlert.ts
Normal file
24
src/components/composable/useAlert.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { useToast } from "primevue/usetoast";
|
||||
import type IVAlert from "@/components/alert/IVAlert.type";
|
||||
|
||||
export function useAlert() {
|
||||
const toast = useToast();
|
||||
|
||||
const showAlert = ({
|
||||
title = '',
|
||||
description = '',
|
||||
type = 'info',
|
||||
closeable = true,
|
||||
lifeTime,
|
||||
}: IVAlert) => {
|
||||
toast.add({
|
||||
severity: type,
|
||||
summary: title,
|
||||
detail: description,
|
||||
life: lifeTime,
|
||||
closable: closeable,
|
||||
})
|
||||
}
|
||||
|
||||
return { showAlert}
|
||||
}
|
|
@ -2,9 +2,11 @@ import './assets/main.css'
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import primeVue from 'primevue/config'
|
||||
import ToastService from 'primevue/toastservice'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(primeVue)
|
||||
app.use(ToastService)
|
||||
|
||||
app.mount('#app')
|
||||
|
|
60
test/VAlert.spec.ts
Normal file
60
test/VAlert.spec.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
import { mount, flushPromises } from '@vue/test-utils';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import VAlert from '../src/components/alert/VAlert.vue';
|
||||
import Toast from 'primevue/toast';
|
||||
import ToastService from 'primevue/toastservice';
|
||||
|
||||
vi.mock('primevue/toastservice', () => ({
|
||||
default: {
|
||||
install: () => {},
|
||||
add: vi.fn()
|
||||
}
|
||||
}));
|
||||
|
||||
describe('VAlert.vue', () => {
|
||||
let wrapper: ReturnType<typeof mount>;
|
||||
|
||||
beforeEach(() => {
|
||||
const container = document.createElement('div');
|
||||
container.id = 'app';
|
||||
document.body.appendChild(container);
|
||||
|
||||
wrapper = mount(VAlert, {
|
||||
attachTo: '#app',
|
||||
global: {
|
||||
components: { Toast },
|
||||
plugins: [ToastService]
|
||||
},
|
||||
props: {
|
||||
position: 'top-right'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 💡 Helper pour injecter un toast et attendre le rendu
|
||||
const renderToast = async (payload: { severity: string; summary: string; detail: string; life: number }) => {
|
||||
wrapper.vm.$toast?.add(payload);
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
await flushPromises();
|
||||
};
|
||||
|
||||
it('renders the Toast container via teleport', async () => {
|
||||
await renderToast({
|
||||
severity: 'success',
|
||||
summary: 'Test Title',
|
||||
detail: 'Test description',
|
||||
life: 3000
|
||||
});
|
||||
|
||||
const toast = document.querySelector('.p-toast');
|
||||
expect(toast).toBeTruthy();
|
||||
});
|
||||
|
||||
it('responds to "close" and "life-end" events', async () => {
|
||||
await wrapper.vm.$emit('close', { id: 'test-alert' });
|
||||
await wrapper.vm.$emit('life-end', { id: 'test-alert' });
|
||||
|
||||
expect(wrapper.emitted()).toHaveProperty('close');
|
||||
expect(wrapper.emitted()).toHaveProperty('life-end');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user