Compare commits
50 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
299bae8d3d | ||
|
ef93944618 | ||
|
cff17612de | ||
|
6af37991a4 | ||
|
6a0e9e566b | ||
|
b06accb14f | ||
|
9e3067627c | ||
|
fd143ea7a5 | ||
|
5f5c532d8e | ||
|
e20626296e | ||
|
96fa281b11 | ||
|
8d4bb9b762 | ||
|
dcf54bf4b9 | ||
|
6caad49ff8 | ||
|
24b1018f7a | ||
|
501e9cb3b8 | ||
|
8071f3565c | ||
|
fff3f5e647 | ||
|
1ca5f60449 | ||
|
07aed8835e | ||
|
3c3956da68 | ||
|
65a2f9028a | ||
|
2bd148274f | ||
|
ae4955f00c | ||
|
8bfd244be2 | ||
|
921667d7e9 | ||
|
ce70f81113 | ||
|
504118e92e | ||
|
073ddc9d7c | ||
|
994237e98e | ||
|
625189077b | ||
|
dc288d42bb | ||
|
ef57a78a03 | ||
|
38dfcfe794 | ||
|
f8dfcfee1f | ||
|
34a00841b1 | ||
|
8f77be03dc | ||
|
7749fdc8e2 | ||
|
1fb81ec69f | ||
|
738f5ae2ad | ||
|
a5ef570311 | ||
|
1964852b1c | ||
|
3c833bacb1 | ||
|
e960c0d56d | ||
|
b78de670e9 | ||
|
edeb8b105d | ||
|
cf208cd03b | ||
|
fee74298c0 | ||
|
45c3945627 | ||
|
efc442316c |
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -5,6 +5,18 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.28] - 2025-08-11
|
||||||
|
### fixed
|
||||||
|
- bug fixed
|
||||||
|
|
||||||
|
## [1.0.24] - 2025-08-02
|
||||||
|
### fixed
|
||||||
|
- Composable error fixed
|
||||||
|
|
||||||
|
## [1.0.22] - 2025-08-02
|
||||||
|
### fixed
|
||||||
|
- Fixed bugs related to dependencies
|
||||||
|
|
||||||
## [1.0.20] - 2025-07-31
|
## [1.0.20] - 2025-07-31
|
||||||
### fixed
|
### fixed
|
||||||
- Composable error fixed
|
- Composable error fixed
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# visua-vue
|
# visua-vue
|
||||||
|
|
||||||
**Current version: v1.0.20**
|
**Current version: v1.0.28**
|
1293
package-lock.json
generated
1293
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@cellule-financiere-pmo/visua-vue",
|
"name": "@cellule-financiere-pmo/visua-vue",
|
||||||
"version": "1.0.20",
|
"version": "1.0.28",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Vue.js components of the Visua Design System.",
|
"description": "Vue.js components of the Visua Design System.",
|
||||||
"main": "./dist/visua-vue.umd.cjs",
|
"main": "./dist/visua-vue.umd.cjs",
|
||||||
|
@ -32,14 +32,13 @@
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cellule-financiere-pmo/visua": "1.1.3",
|
"@cellule-financiere-pmo/visua": "1.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
"primevue": "^4.3.6",
|
"primevue": "^4.3.6",
|
||||||
"vue": "^3.5.17",
|
"vue": "^3.5.17",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.5.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
|
||||||
"vue": "^3.5.17"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node22": "^22.0.2",
|
"@tsconfig/node22": "^22.0.2",
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.32",
|
||||||
|
@ -51,6 +50,7 @@
|
||||||
"eslint": "^9.29.0",
|
"eslint": "^9.29.0",
|
||||||
"eslint-plugin-vue": "~10.2.0",
|
"eslint-plugin-vue": "~10.2.0",
|
||||||
"jiti": "^2.4.2",
|
"jiti": "^2.4.2",
|
||||||
|
"jsdom": "^26.1.0",
|
||||||
"npm-run-all2": "^8.0.4",
|
"npm-run-all2": "^8.0.4",
|
||||||
"rimraf": "^5.0.10",
|
"rimraf": "^5.0.10",
|
||||||
"typescript": "~5.8.0",
|
"typescript": "~5.8.0",
|
||||||
|
@ -58,6 +58,8 @@
|
||||||
"vite-plugin-inspect": "^11.3.0",
|
"vite-plugin-inspect": "^11.3.0",
|
||||||
"vite-plugin-vue-devtools": "^7.7.7",
|
"vite-plugin-vue-devtools": "^7.7.7",
|
||||||
"vitest": "^3.2.4",
|
"vitest": "^3.2.4",
|
||||||
|
"vue": "^3.5.17",
|
||||||
|
"vue-router": "^4.5.1",
|
||||||
"vue-tsc": "^2.2.10"
|
"vue-tsc": "^2.2.10"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
// import VConfirmModalView from '../template/VConfirmModalView.vue';
|
// import VConfirmModalView from '../template/VConfirmModalView.vue';
|
||||||
import VDataTableView from '../template/VDataTableView.vue';
|
import VDataTableView from '../template/VDataTableView.vue';
|
||||||
// import VMenuBarView from '../template/VMenuBarView.vue'
|
// import VMenuBarView from '../template/VMenuBarView.vue'
|
||||||
|
// import VDataTable from './components/table/VDataTable.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,8 +26,8 @@ import VDataTableView from '../template/VDataTableView.vue';
|
||||||
<!-- <VAccordionView/> -->
|
<!-- <VAccordionView/> -->
|
||||||
<!-- <VInputView/> -->
|
<!-- <VInputView/> -->
|
||||||
<!-- <VCheckboxView/> -->
|
<!-- <VCheckboxView/> -->
|
||||||
<!-- <VBadgeView/>
|
<!-- <VBadgeView/>-->
|
||||||
<VSelectView/> -->
|
<!-- <VSelectView/> -->
|
||||||
<!-- <VProgressBarView/> -->
|
<!-- <VProgressBarView/> -->
|
||||||
<!-- <VMessageView/> -->
|
<!-- <VMessageView/> -->
|
||||||
<!-- <VFileUploadView/> -->
|
<!-- <VFileUploadView/> -->
|
||||||
|
@ -35,7 +36,8 @@ import VDataTableView from '../template/VDataTableView.vue';
|
||||||
<!-- <VConfirmModalView/> -->
|
<!-- <VConfirmModalView/> -->
|
||||||
<VDataTableView/>
|
<VDataTableView/>
|
||||||
<!-- <RouterView/> -->
|
<!-- <RouterView/> -->
|
||||||
<VMenuBarView/>
|
<!-- <VMenuBarView/> -->
|
||||||
|
<!-- <VDataTable/> -->
|
||||||
</template>
|
</template>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
*{
|
*{
|
||||||
|
|
|
@ -53,21 +53,21 @@
|
||||||
--p-datatable-footer-border-color: var(--p-datatable-border-color);
|
--p-datatable-footer-border-color: var(--p-datatable-border-color);
|
||||||
--p-datatable-footer-color: var(--p-content-color);
|
--p-datatable-footer-color: var(--p-content-color);
|
||||||
--p-datatable-footer-border-width: 0 0 1px 0;
|
--p-datatable-footer-border-width: 0 0 1px 0;
|
||||||
--p-datatable-footer-padding: 1rem;
|
--p-datatable-footer-padding: 0.75rem;
|
||||||
--p-datatable-footer-lg-padding: 1.25rem;
|
--p-datatable-footer-lg-padding: 1rem;
|
||||||
--p-datatable-footer-sm-padding: 0.5rem;
|
--p-datatable-footer-sm-padding: 0.5rem;
|
||||||
--p-datatable-column-footer-font-weight: 600;
|
--p-datatable-column-footer-font-weight: 600;
|
||||||
--p-datatable-footer-cell-background: var(--datatable-background);
|
--p-datatable-footer-cell-background: var(--datatable-background);
|
||||||
--p-datatable-footer-cell-border-color: var(--p-datatable-border-color);
|
--p-datatable-footer-cell-border-color: var(--p-datatable-border-color);
|
||||||
--p-datatable-footer-cell-color: var(--p-content-color);
|
--p-datatable-footer-cell-color: var(--p-content-color);
|
||||||
--p-datatable-footer-cell-padding: 1rem;
|
--p-datatable-footer-cell-padding: 0.75rem;
|
||||||
--p-datatable-footer-cell-lg-padding: 1.25rem;
|
--p-datatable-footer-cell-lg-padding: 1rem;
|
||||||
--p-datatable-footer-cell-sm-padding: 0.5rem;
|
--p-datatable-footer-cell-sm-padding: 0.5rem;
|
||||||
--p-datatable-body-cell-border-color: var(--p-datatable-border-color);
|
--p-datatable-body-cell-border-color: var(--p-datatable-border-color);
|
||||||
--p-datatable-body-cell-padding: 1rem;
|
--p-datatable-body-cell-padding: 0.75rem;
|
||||||
--p-datatable-body-cell-lg-padding: 1.25rem;
|
--p-datatable-body-cell-lg-padding: 1rem;
|
||||||
--p-datatable-body-cell-sm-padding: 0.5rem;
|
--p-datatable-body-cell-sm-padding: 0.5rem;
|
||||||
--p-datatable-row-background: var(--datatable-alt-background);
|
--p-datatable-row-background: var(--datatable-background);
|
||||||
--p-datatable-row-hover-background: var(--datatable-hover-background);
|
--p-datatable-row-hover-background: var(--datatable-hover-background);
|
||||||
--p-datatable-row-selected-background: var(--datatable-active-background);
|
--p-datatable-row-selected-background: var(--datatable-active-background);
|
||||||
--p-datatable-row-color: var(--datatable-row-color);
|
--p-datatable-row-color: var(--datatable-row-color);
|
||||||
|
@ -78,17 +78,17 @@
|
||||||
--p-datatable-row-focus-ring-color: var(--focus-color);
|
--p-datatable-row-focus-ring-color: var(--focus-color);
|
||||||
--p-datatable-row-focus-ring-offset: -1px;
|
--p-datatable-row-focus-ring-offset: -1px;
|
||||||
/* --p-datatable-row-focus-ring-shadow: var(--p-focus-ring-shadow); */
|
/* --p-datatable-row-focus-ring-shadow: var(--p-focus-ring-shadow); */
|
||||||
--p-datatable-column-title-font-weight: var(--text-body-SM-detail-text-Bold-weight);
|
--p-datatable-column-title-font-weight: var(--text-body-SM-detail-text-Medium-weight);
|
||||||
--p-datatable-header-cell-background: var(--datatable-background);
|
--p-datatable-header-cell-background: var(--primary-color-850-blue-france-default);
|
||||||
--p-datatable-header-cell-hover-background: var(--datatable-hover-background);
|
--p-datatable-header-cell-hover-background: var(--primary-color-850-blue-france-hover);
|
||||||
--p-datatable-header-cell-selected-background: var(--datatable-active-background);
|
--p-datatable-header-cell-selected-background: var(--primary-color-850-blue-france-active);
|
||||||
--p-datatable-header-cell-border-color: var(--border-plain-grey);
|
--p-datatable-header-cell-border-color: var(--border-plain-grey);
|
||||||
--p-datatable-header-cell-color: var(--datatable-header-cell-color);
|
--p-datatable-header-cell-color: var(--datatable-header-cell-color);
|
||||||
--p-datatable-header-cell-hover-color: var(--datatable-header-cell-color);
|
--p-datatable-header-cell-hover-color: var(--datatable-header-cell-color);
|
||||||
--p-datatable-header-cell-selected-color: var(--datatable-header-cell-color);
|
--p-datatable-header-cell-selected-color: var(--datatable-header-cell-color);
|
||||||
--p-datatable-header-cell-gap: 0.5rem;
|
--p-datatable-header-cell-gap: 0.5rem;
|
||||||
--p-datatable-header-cell-padding: 1rem;
|
--p-datatable-header-cell-padding: 0.75rem;
|
||||||
--p-datatable-header-cell-lg-padding: 1.25rem;
|
--p-datatable-header-cell-lg-padding: 1rem;
|
||||||
--p-datatable-header-cell-sm-padding: 0.5rem;
|
--p-datatable-header-cell-sm-padding: 0.5rem;
|
||||||
--p-datatable-header-cell-focus-ring-width: var(--focus-width);
|
--p-datatable-header-cell-focus-ring-width: var(--focus-width);
|
||||||
--p-datatable-header-cell-focus-ring-style: var(--focus-style);
|
--p-datatable-header-cell-focus-ring-style: var(--focus-style);
|
||||||
|
@ -96,11 +96,11 @@
|
||||||
--p-datatable-header-cell-focus-ring-offset: -1px;
|
--p-datatable-header-cell-focus-ring-offset: -1px;
|
||||||
/* --p-datatable-header-cell-focus-ring-shadow: var(--p-focus-ring-shadow); */
|
/* --p-datatable-header-cell-focus-ring-shadow: var(--p-focus-ring-shadow); */
|
||||||
--p-datatable-header-background: var(--datatable-background);
|
--p-datatable-header-background: var(--datatable-background);
|
||||||
--p-datatable-header-border-color: var(--border-default-grey);
|
--p-datatable-header-border-color: transparent;
|
||||||
--p-datatable-header-color: var(--datatable-header-cell-color);
|
--p-datatable-header-color: var(--datatable-header-cell-color);
|
||||||
--p-datatable-header-border-width: 0 0 1px 0;
|
--p-datatable-header-border-width: 0 0 1px 0;
|
||||||
--p-datatable-header-padding: 1rem;
|
--p-datatable-header-padding: 0.75rem;
|
||||||
--p-datatable-header-lg-padding: 1.25rem;
|
--p-datatable-header-lg-padding: 1rem;
|
||||||
--p-datatable-header-sm-padding: 0.5rem;
|
--p-datatable-header-sm-padding: 0.5rem;
|
||||||
/* --p-datatable-transition-duration: var(--p-transition-duration); */
|
/* --p-datatable-transition-duration: var(--p-transition-duration); */
|
||||||
--p-datatable-body-cell-selected-border-color: var(--datatable-active-background);
|
--p-datatable-body-cell-selected-border-color: var(--datatable-active-background);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
--p-fileupload-header-border-width: 0;
|
--p-fileupload-header-border-width: 0;
|
||||||
--p-fileupload-header-border-radius: 0;
|
--p-fileupload-header-border-radius: 0;
|
||||||
--p-fileupload-header-gap: 0.5rem;
|
--p-fileupload-header-gap: 0.5rem;
|
||||||
--p-fileupload-background: var(--background-transparent);
|
--p-fileupload-background: var(--background-default-grey);
|
||||||
--p-fileupload-border-color: var(--border-default-grey);
|
--p-fileupload-border-color: var(--border-default-grey);
|
||||||
--p-fileupload-color: var(--text-default-grey);
|
--p-fileupload-color: var(--text-default-grey);
|
||||||
--p-fileupload-border-radius: 0px;
|
--p-fileupload-border-radius: 0px;
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { useToast } from "primevue/usetoast";
|
import { useToast } from "primevue/usetoast";
|
||||||
import type IVAlert from "@/components/alert/IVAlert.type.js";
|
import type IVAlert from "../alert/IVAlert.type.js";
|
||||||
|
|
||||||
export function useAlert() {
|
export function useAlert() {
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
const showAlert = ({
|
const showAlert = ({
|
||||||
title = '',
|
title = '',
|
||||||
description = '',
|
description = '',
|
||||||
|
@ -9,17 +11,14 @@ export function useAlert() {
|
||||||
closeable = true,
|
closeable = true,
|
||||||
lifeTime,
|
lifeTime,
|
||||||
}: IVAlert) => {
|
}: IVAlert) => {
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: type,
|
severity: type,
|
||||||
summary: title,
|
summary: title,
|
||||||
detail: description,
|
detail: description,
|
||||||
life: lifeTime,
|
life: lifeTime,
|
||||||
closable: closeable,
|
closable: closeable,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
return { showAlert };
|
return { showAlert}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { useConfirm } from "primevue";
|
||||||
import VButton from "../button/VButton.vue";
|
import VButton from "../button/VButton.vue";
|
||||||
|
|
||||||
export function useConfirmModal() {
|
export function useConfirmModal() {
|
||||||
|
const confirm = useConfirm();
|
||||||
|
|
||||||
const showConfirmModal = ({
|
const showConfirmModal = ({
|
||||||
acceptProps = VButton,
|
acceptProps = VButton,
|
||||||
rejectProps = VButton,
|
rejectProps = VButton,
|
||||||
|
@ -10,17 +12,15 @@ export function useConfirmModal() {
|
||||||
header = '',
|
header = '',
|
||||||
message = '',
|
message = '',
|
||||||
icon = '',
|
icon = '',
|
||||||
accept = () => {},
|
accept = Function,
|
||||||
reject = () => {},
|
reject = Function,
|
||||||
onHide = () => {},
|
onHide = Function,
|
||||||
onShow = () => {},
|
onShow = Function,
|
||||||
modal = true,
|
modal = true,
|
||||||
blockScroll = true,
|
blockScroll = true,
|
||||||
position = 'center',
|
position = 'center',
|
||||||
appendTo = 'body',
|
appendTo = 'body',
|
||||||
}: ConfirmationOptions) => {
|
}: ConfirmationOptions) => {
|
||||||
const confirm = useConfirm();
|
|
||||||
|
|
||||||
confirm.require({
|
confirm.require({
|
||||||
group,
|
group,
|
||||||
header,
|
header,
|
||||||
|
@ -36,9 +36,7 @@ export function useConfirmModal() {
|
||||||
blockScroll,
|
blockScroll,
|
||||||
position,
|
position,
|
||||||
appendTo,
|
appendTo,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
return {showConfirmModal}
|
||||||
return { showConfirmModal };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,11 @@ import styles from '@visua/typography.module.css';
|
||||||
|
|
||||||
const fileUploadRef = ref();
|
const fileUploadRef = ref();
|
||||||
const fileProgressMap = ref<Record<string, number>>({});
|
const fileProgressMap = ref<Record<string, number>>({});
|
||||||
const hasActiveError = ref(false);
|
const hasValidationError = ref(false);
|
||||||
|
const hasSystemError = ref(false);
|
||||||
|
const systemErrorMessage = ref('');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
@ -72,7 +76,6 @@ const handleSelect = (event: FileUploadSelectEvent) => {
|
||||||
|
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
emit('clear');
|
emit('clear');
|
||||||
hasActiveError.value = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpload = (event: FileUploadUploadEvent) => {
|
const handleUpload = (event: FileUploadUploadEvent) => {
|
||||||
|
@ -81,7 +84,6 @@ const handleUpload = (event: FileUploadUploadEvent) => {
|
||||||
|
|
||||||
const handleRemove = (event: FileUploadRemoveEvent) => {
|
const handleRemove = (event: FileUploadRemoveEvent) => {
|
||||||
emit('remove', event);
|
emit('remove', event);
|
||||||
hasActiveError.value =false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleProgress = (event: FileUploadProgressEvent) => {
|
const handleProgress = (event: FileUploadProgressEvent) => {
|
||||||
|
@ -95,11 +97,21 @@ const handleProgress = (event: FileUploadProgressEvent) => {
|
||||||
|
|
||||||
const handleError = (event: FileUploadErrorEvent) => {
|
const handleError = (event: FileUploadErrorEvent) => {
|
||||||
emit('error', event);
|
emit('error', event);
|
||||||
hasActiveError.value = true;
|
hasSystemError.value = true;
|
||||||
|
|
||||||
|
const status = event.xhr?.status;
|
||||||
|
const statusText = event.xhr?.statusText || 'Erreur inconnue';
|
||||||
|
const fileNames = Array.isArray(event.files)
|
||||||
|
? event.files.map(f => f.name).join(', ')
|
||||||
|
: event.files.name;
|
||||||
|
|
||||||
|
systemErrorMessage.value = `Echec de téléversement du fichier ${fileNames} {Status : ${status} | Message : <${statusText}>}`;
|
||||||
|
|
||||||
if (!props.advanced && fileUploadRef.value) {
|
if (!props.advanced && fileUploadRef.value) {
|
||||||
fileUploadRef.value.uploadedFiles = [];
|
fileUploadRef.value.uploadedFiles = [];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const lastSelectedFile = computed(() => {
|
const lastSelectedFile = computed(() => {
|
||||||
const files = fileUploadRef.value?.files || [];
|
const files = fileUploadRef.value?.files || [];
|
||||||
|
@ -114,10 +126,10 @@ const padding = computed(() => props.advanced ? '1.125rem' : '0rem')
|
||||||
const borderColor = computed(() => props.advanced ? 'var(--border-default-grey)' : 'transparent');
|
const borderColor = computed(() => props.advanced ? 'var(--border-default-grey)' : 'transparent');
|
||||||
|
|
||||||
const labelState = computed(() => {
|
const labelState = computed(() => {
|
||||||
if(!hasActiveError.value && !props.disabled) return 'default';
|
if ((hasValidationError.value || hasSystemError.value) && !props.disabled) return 'error';
|
||||||
else if(hasActiveError.value && !props.disabled) return 'error';
|
return 'default';
|
||||||
else return undefined
|
});
|
||||||
})
|
|
||||||
|
|
||||||
type MessageType = 'alert' | 'warning' | 'success' | 'info';
|
type MessageType = 'alert' | 'warning' | 'success' | 'info';
|
||||||
|
|
||||||
|
@ -222,21 +234,21 @@ const globalStatusMessage = computed<{
|
||||||
title="parcourir les fichiers"
|
title="parcourir les fichiers"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="(!slotProps.files || slotProps.files.length === 0) && (!slotProps.uploadedFiles || slotProps.uploadedFiles.length === 0) && !hasActiveError"
|
v-if="(!slotProps.files || slotProps.files.length === 0) && (!slotProps.uploadedFiles || slotProps.uploadedFiles.length === 0) && !(hasSystemError || hasValidationError)"
|
||||||
:class="[styles['text-body-SM-detail-text-Regular']]"
|
:class="[styles['text-body-SM-detail-text-Regular']]"
|
||||||
>
|
>
|
||||||
Aucun fichier sélectionné
|
Aucun fichier sélectionné
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #empty v-if="props.advanced && !hasActiveError">
|
<template #empty v-if="props.advanced && !(hasSystemError || hasValidationError)">
|
||||||
<div class="fileupload-empty" :class="[styles['text-body-SM-detail-text-Regular']]">
|
<div class="fileupload-empty" :class="[styles['text-body-SM-detail-text-Regular']]">
|
||||||
<i class="ri-upload-cloud-line upload-cloud-icon"></i>
|
<i class="ri-upload-cloud-line upload-cloud-icon"></i>
|
||||||
<p>Glissez-déposez les fichiers ici pour les téléverser.</p>
|
<p>Glissez-déposez les fichiers ici pour les téléverser.</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #content="slotProps">
|
<template #content="slotProps">
|
||||||
<div v-if="props.advanced && !hasActiveError" style="margin-top: 0.75rem;" class="file-content">
|
<div v-if="props.advanced && !(hasValidationError || hasSystemError)" style="margin-top: 0.75rem;" class="file-content">
|
||||||
<VMessage
|
<VMessage
|
||||||
v-if="globalStatusMessage"
|
v-if="globalStatusMessage"
|
||||||
:type="globalStatusMessage.type"
|
:type="globalStatusMessage.type"
|
||||||
|
@ -271,7 +283,7 @@ const globalStatusMessage = computed<{
|
||||||
</div>
|
</div>
|
||||||
</VScrollPanel>
|
</VScrollPanel>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!props.advanced && !hasActiveError">
|
<div v-if="!props.advanced && !(hasValidationError || hasSystemError)">
|
||||||
<VFile
|
<VFile
|
||||||
v-if="lastSelectedFile"
|
v-if="lastSelectedFile"
|
||||||
:file="lastSelectedFile"
|
:file="lastSelectedFile"
|
||||||
|
@ -290,14 +302,17 @@ const globalStatusMessage = computed<{
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
>
|
>
|
||||||
<VHint
|
<VHint
|
||||||
v-for="message of slotProps.messages"
|
v-for="message of [...(slotProps.messages ?? []), ...(hasSystemError ? [systemErrorMessage] : [])]"
|
||||||
:key="message"
|
:key="message"
|
||||||
:title="message"
|
:title="message"
|
||||||
type="alert"
|
type="alert"
|
||||||
icon
|
icon
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<VLabelErrorProxy :hasError="(slotProps.messages ?? []).length > 0" @update:error="hasActiveError = $event" />
|
<VLabelErrorProxy
|
||||||
|
:hasError="(slotProps.messages ?? []).length > 0"
|
||||||
|
@update:error="hasValidationError = $event"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</FileUpload>
|
</FileUpload>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -70,7 +70,7 @@ const labelState = computed(() => {
|
||||||
v-if="props.labelVisible"
|
v-if="props.labelVisible"
|
||||||
:for="props.id"
|
:for="props.id"
|
||||||
:label="props.label"
|
:label="props.label"
|
||||||
:required="!props.disabled"
|
:required="!props.disabled && props.required"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
:type="labelState"
|
:type="labelState"
|
||||||
:hint="props.hint"
|
:hint="props.hint"
|
||||||
|
|
|
@ -14,6 +14,7 @@ const props = withDefaults(defineProps<IVLabel>(), {
|
||||||
<template>
|
<template>
|
||||||
<label
|
<label
|
||||||
:for="props.for"
|
:for="props.for"
|
||||||
|
class="label-container"
|
||||||
:class="[styles['text-body-MD-standard-text-Regular'], {
|
:class="[styles['text-body-MD-standard-text-Regular'], {
|
||||||
'label': props.type === 'default',
|
'label': props.type === 'default',
|
||||||
'success': props.type === 'success',
|
'success': props.type === 'success',
|
||||||
|
@ -23,12 +24,14 @@ const props = withDefaults(defineProps<IVLabel>(), {
|
||||||
:aria-label="props.label"
|
:aria-label="props.label"
|
||||||
:aria-disabled="props.disabled"
|
:aria-disabled="props.disabled"
|
||||||
>
|
>
|
||||||
|
<span>
|
||||||
{{ props.label }}
|
{{ props.label }}
|
||||||
<template v-if="props.required">
|
<template v-if="props.required">
|
||||||
<span v-if="props.required" :class="{ 'required': !props.disabled}">
|
<span v-if="props.required" :class="{ 'required': !props.disabled}">
|
||||||
<slot name="required-tip">*</slot>
|
<slot name="required-tip">*</slot>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
</span>
|
||||||
<VHint
|
<VHint
|
||||||
v-if="props.hint"
|
v-if="props.hint"
|
||||||
:title="props.hint"
|
:title="props.hint"
|
||||||
|
@ -38,6 +41,18 @@ const props = withDefaults(defineProps<IVLabel>(), {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
|
*{
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-container{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: start;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.label {color: var(--text-label-grey);}
|
.label {color: var(--text-label-grey);}
|
||||||
.success {color: var(--text-default-success);}
|
.success {color: var(--text-default-success);}
|
||||||
.error {color: var(--text-default-error);}
|
.error {color: var(--text-default-error);}
|
||||||
|
|
|
@ -86,6 +86,8 @@ export default interface IVMenuBar {
|
||||||
|
|
||||||
/** Responsive breakpoints (e.g. Tailwind-style classes) */
|
/** Responsive breakpoints (e.g. Tailwind-style classes) */
|
||||||
breakpoints?: string;
|
breakpoints?: string;
|
||||||
|
|
||||||
|
logoPath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import Menubar from 'primevue/menubar';
|
import Menubar from 'primevue/menubar';
|
||||||
import type IVMenuBar from './IVMenuBar.type.js';
|
import type IVMenuBar from './IVMenuBar.type.js';
|
||||||
import styles from '@visua/typography.module.css'
|
import styles from '@visua/typography.module.css'
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<IVMenuBar>(), {
|
const props = withDefaults(defineProps<IVMenuBar>(), {
|
||||||
searchbarId: 'searchbar-header',
|
searchbarId: 'searchbar-header',
|
||||||
|
@ -11,8 +12,11 @@ const props = withDefaults(defineProps<IVMenuBar>(), {
|
||||||
logoText: undefined,
|
logoText: undefined,
|
||||||
breakpoints: '960px',
|
breakpoints: '960px',
|
||||||
quickLinks: undefined,
|
quickLinks: undefined,
|
||||||
menuLabel: undefined
|
menuLabel: undefined,
|
||||||
|
logoPath: '/home',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -23,7 +27,7 @@ const props = withDefaults(defineProps<IVMenuBar>(), {
|
||||||
class="p-menubar"
|
class="p-menubar"
|
||||||
>
|
>
|
||||||
<template #start>
|
<template #start>
|
||||||
<RouterLink to="/" class="logo-container">
|
<RouterLink :to=props.logoPath class="logo-container">
|
||||||
<div v-if="$slots.logo" class="logo">
|
<div v-if="$slots.logo" class="logo">
|
||||||
<slot name="logo"/>
|
<slot name="logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,7 +53,9 @@ const props = withDefaults(defineProps<IVMenuBar>(), {
|
||||||
:tabindex="0"
|
:tabindex="0"
|
||||||
v-bind="props.action"
|
v-bind="props.action"
|
||||||
class="item"
|
class="item"
|
||||||
:class="[styles['text-body-LG-article-text-Regular']]"
|
:class="[styles['text-body-LG-article-text-Regular'],
|
||||||
|
item.to === route.path ? 'active' : ''
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<slot name="itemicon" :item="item" v-if="'icon' in item">
|
<slot name="itemicon" :item="item" v-if="'icon' in item">
|
||||||
<i :class="[item.icon]"></i>
|
<i :class="[item.icon]"></i>
|
||||||
|
@ -104,7 +110,13 @@ a{
|
||||||
}
|
}
|
||||||
|
|
||||||
.item:hover,
|
.item:hover,
|
||||||
.item:active{
|
.item.active{
|
||||||
color: var(--menu-active-color);
|
color: var(--menu-active-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item.active {
|
||||||
|
height: 100%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Select from 'primevue/select';
|
import Select, { type SelectSlots } from 'primevue/select';
|
||||||
import type IVSelect from './IVSelect.type.js';
|
import type IVSelect from './IVSelect.type.js';
|
||||||
import { useId, computed, watch, ref } from 'vue';
|
import { useId, computed, watch, ref } from 'vue';
|
||||||
import VLabel from '../label/VLabel.vue';
|
import VLabel from '../label/VLabel.vue';
|
||||||
|
@ -29,9 +29,7 @@ const props = withDefaults(defineProps<IVSelect>(), {
|
||||||
selectionMessage: 'Elements sélectionnés',
|
selectionMessage: 'Elements sélectionnés',
|
||||||
emptySelectionMessage: 'Aucun élément sélectionné',
|
emptySelectionMessage: 'Aucun élément sélectionné',
|
||||||
emptyFilterMessage: 'Aucun résultat trouvé',
|
emptyFilterMessage: 'Aucun résultat trouvé',
|
||||||
emptyMessage: 'Aucune option disponible',
|
emptyMessage: 'Aucune option disponible'
|
||||||
optionTemplate: false,
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
|
@ -78,6 +76,33 @@ const labelState = computed(() => {
|
||||||
else if(props.errorMessage && !props.successMessage && !props.disabled) return 'error';
|
else if(props.errorMessage && !props.successMessage && !props.disabled) return 'error';
|
||||||
else return undefined
|
else return undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
type VSelectSlots = SelectSlots & {
|
||||||
|
required?: (props: Record<string, unknown>) => unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
const slots = defineSlots<VSelectSlots>();
|
||||||
|
|
||||||
|
const selectSlotKeys = [
|
||||||
|
'value',
|
||||||
|
'header',
|
||||||
|
'footer',
|
||||||
|
'option',
|
||||||
|
'optiongroup',
|
||||||
|
'emptyfilter',
|
||||||
|
'empty',
|
||||||
|
'content',
|
||||||
|
'loader',
|
||||||
|
'clearicon',
|
||||||
|
'dropdownicon',
|
||||||
|
'loadingicon',
|
||||||
|
'filtericon'
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const availableSlots = computed(() =>
|
||||||
|
selectSlotKeys.filter((key) => !!slots[key]).map((key) => [key, slots[key]])
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -86,13 +111,13 @@ const labelState = computed(() => {
|
||||||
v-if="props.label"
|
v-if="props.label"
|
||||||
:for="props.selectId"
|
:for="props.selectId"
|
||||||
:label="props.label"
|
:label="props.label"
|
||||||
:required="!props.disabled"
|
:required="props.required && !props.disabled"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
:type="labelState"
|
:type="labelState"
|
||||||
:hint="props.hint"
|
:hint="props.hint"
|
||||||
>
|
>
|
||||||
<template #required-type v-if="props.required">
|
<template #required-type v-if="props.required">
|
||||||
<slot name="required-type"/>
|
<slot name="required"/>
|
||||||
</template>
|
</template>
|
||||||
</VLabel>
|
</VLabel>
|
||||||
<Select
|
<Select
|
||||||
|
@ -141,8 +166,12 @@ const labelState = computed(() => {
|
||||||
}
|
}
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<template v-if="props.optionTemplate" #option="{option, selected, index}">
|
<template
|
||||||
<slot name="option" :option="option" :selected="selected" :index="index"/>
|
v-for="([name]) in availableSlots"
|
||||||
|
:key="name"
|
||||||
|
v-slot:[name]="slotProps"
|
||||||
|
>
|
||||||
|
<slot :name="name" v-bind="slotProps" />
|
||||||
</template>
|
</template>
|
||||||
</Select>
|
</Select>
|
||||||
<div
|
<div
|
||||||
|
@ -174,6 +203,8 @@ const labelState = computed(() => {
|
||||||
--p-select-dropdown-color: var(--text-disabled-grey);
|
--p-select-dropdown-color: var(--text-disabled-grey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-select.error, .p-select.success{border-width: var(--large-border-width);}
|
||||||
|
|
||||||
.p-select.error{
|
.p-select.error{
|
||||||
--p-select-border-color: var(--border-plain-error);
|
--p-select-border-color: var(--border-plain-error);
|
||||||
--p-select-hover-border-color: var(--border-plain-error);
|
--p-select-hover-border-color: var(--border-plain-error);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import DataTable from 'primevue/datatable';
|
import DataTable from 'primevue/datatable';
|
||||||
import type { DataTableProps, DataTableSlots } from 'primevue/datatable';
|
import type { DataTableProps, DataTableSlots } from 'primevue/datatable';
|
||||||
import { useId, ref, watch, computed } from 'vue';
|
import { useId, ref, watch, computed } from 'vue';
|
||||||
|
import styles from '@visua/typography.module.css';
|
||||||
|
|
||||||
export interface IVDataTable extends Partial<Omit<DataTableProps, 'pt' | 'dt' | 'ptOptions' | 'unstyled'>>{
|
export interface IVDataTable extends Partial<Omit<DataTableProps, 'pt' | 'dt' | 'ptOptions' | 'unstyled'>>{
|
||||||
id?: string
|
id?: string
|
||||||
|
@ -415,11 +416,31 @@ watch(localEditingRows, (newVal) => {
|
||||||
<slot :name="name" v-bind="slotProps" />
|
<slot :name="name" v-bind="slotProps" />
|
||||||
</template>
|
</template>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
<template #empty>
|
||||||
|
<div class="datatable-empty" :class="[styles['text-body-SM-detail-text-Regular']]">
|
||||||
|
<i class="ri-database-line database-icon"></i>
|
||||||
|
<span> Aucune donnée trouvée. </span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.p-datatable{
|
.datatable-empty{
|
||||||
|
height: fit-content;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.database-icon{
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
display: block;
|
||||||
|
color: var(--border-contrast-grey);
|
||||||
|
font-size: 5rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { describe, it, expect, vi } from 'vitest'
|
|
||||||
|
|
||||||
// 1️⃣ Mock BEFORE importing useAlert
|
|
||||||
const addSpy = vi.fn()
|
|
||||||
vi.mock('primevue/usetoast', () => ({
|
|
||||||
useToast: () => ({
|
|
||||||
add: addSpy
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
|
|
||||||
// 2️⃣ Import le module après que le mock soit actif
|
|
||||||
import { useAlert } from '../src/components/composable/useAlert'
|
|
||||||
|
|
||||||
describe('useAlert', () => {
|
|
||||||
it('should call toast.add with correct options', () => {
|
|
||||||
const { showAlert } = useAlert()
|
|
||||||
|
|
||||||
showAlert({
|
|
||||||
title: 'Test title',
|
|
||||||
description: 'Test description',
|
|
||||||
type: 'warn',
|
|
||||||
closeable: true,
|
|
||||||
lifeTime: 3000,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(addSpy).toHaveBeenCalledWith({
|
|
||||||
severity: 'warn',
|
|
||||||
summary: 'Test title',
|
|
||||||
detail: 'Test description',
|
|
||||||
closable: true,
|
|
||||||
life: 3000,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,34 +0,0 @@
|
||||||
// tests/useConfirmModal.spec.ts
|
|
||||||
import { describe, it, expect, vi } from 'vitest'
|
|
||||||
|
|
||||||
// ✅ Mock AVANT import de useConfirmModal
|
|
||||||
const requireSpy = vi.fn()
|
|
||||||
vi.mock('primevue', () => ({
|
|
||||||
useConfirm: () => ({
|
|
||||||
require: requireSpy
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
|
|
||||||
import { useConfirmModal } from '../src/components/composable/useConfirmModal'
|
|
||||||
|
|
||||||
describe('useConfirmModal', () => {
|
|
||||||
it('should call confirm.require with the given options', () => {
|
|
||||||
const { showConfirmModal } = useConfirmModal()
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
header: 'Confirm Header',
|
|
||||||
message: 'Are you sure?',
|
|
||||||
accept: vi.fn(),
|
|
||||||
reject: vi.fn(),
|
|
||||||
}
|
|
||||||
|
|
||||||
showConfirmModal(options)
|
|
||||||
|
|
||||||
expect(requireSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
||||||
header: 'Confirm Header',
|
|
||||||
message: 'Are you sure?',
|
|
||||||
accept: options.accept,
|
|
||||||
reject: options.reject,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,9 +1,9 @@
|
||||||
// vite.config.ts
|
// vite.config.ts
|
||||||
import { fileURLToPath, URL } from 'node:url';
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue'
|
||||||
import vueDevTools from 'vite-plugin-vue-devtools';
|
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
import path from 'path';
|
import path from 'path'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -24,12 +24,15 @@ export default defineConfig({
|
||||||
formats: ['es', 'umd'],
|
formats: ['es', 'umd'],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['vue'],
|
external: ['vue', 'primevue', 'vue-router', 'primeicons'],
|
||||||
output: {
|
output: {
|
||||||
globals: {
|
globals: {
|
||||||
vue: 'Vue',
|
vue: 'Vue',
|
||||||
|
primevue: 'PrimeVue',
|
||||||
|
'vue-router': 'VueRouter',
|
||||||
|
primeicons: 'primeicons'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user