codevdesign 0.0.34 → 0.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,7 +21,7 @@
21
21
 
22
22
  <v-card-title
23
23
  class="pa-0 ma-0 pb-6"
24
- style="font-size: 24px"
24
+ style="font-size: 24px; white-space: normal; word-break: break-word"
25
25
  >
26
26
  <slot name="titre"></slot>
27
27
  <div class="headline">{{ titre }}</div>
@@ -5,12 +5,13 @@
5
5
  cols="9"
6
6
  md="8"
7
7
  lg="6"
8
+ class="d-flex align-end"
8
9
  >
9
10
  <div class="labelSwitchSiSwitchApres">{{ texte }}</div>
10
11
  </v-col>
11
12
  <v-col
12
13
  cols="2"
13
- class="flex-grow-1 d-flex justify-end pt-0 mt-0 pb-0 mb-0"
14
+ class="d-flex align-end justify-end"
14
15
  >
15
16
  <v-switch
16
17
  v-model="maValeur"
@@ -117,4 +118,7 @@
117
118
  font-weight: bold;
118
119
  margin-top: 25px;
119
120
  }
121
+ .v-switch {
122
+ margin-bottom: -10px; /* aligner le switch avec son texte*/
123
+ }
120
124
  </style>
@@ -69,6 +69,7 @@
69
69
  static
70
70
  :readonly="chargementListe"
71
71
  expand-icon=""
72
+ @update:modelValue="onPanelChange"
72
73
  >
73
74
  <v-expansion-panel
74
75
  flat
@@ -277,7 +278,15 @@
277
278
  Object.values(item).some(val => String(val).toLowerCase().includes(recherche.value.toLowerCase())),
278
279
  )
279
280
  })
280
- const emit = defineEmits(['ajouter', 'cliqueLigne', 'supprimer', 'modifier', 'donneesExportees'])
281
+ const onPanelChange = (val: unknown) => {
282
+ if (typeof val === 'string' || typeof val === 'number' || val === null) {
283
+ const isOpen = val !== null && val !== ''
284
+ emit('panneau:etat', isOpen)
285
+ } else {
286
+ emit('panneau:etat', false)
287
+ }
288
+ }
289
+ const emit = defineEmits(['ajouter', 'cliqueLigne', 'supprimer', 'modifier', 'donneesExportees', 'panneau:etat'])
281
290
  </script>
282
291
 
283
292
  <style scoped lang="css">
@@ -0,0 +1,157 @@
1
+ <template>
2
+ <v-row dense>
3
+ <v-col
4
+ cols="12"
5
+ v-if="afficherChampFr"
6
+ >
7
+ <label
8
+ :for="`saisieChampFr-${cleTradFr}`"
9
+ :class="{ libelle: true, required: estRequis }"
10
+ v-if="!libelleInterieur"
11
+ >{{ $t(cleTradFr) }}</label
12
+ >
13
+ <v-textarea
14
+ :id="`saisieChampFr-${cleTradFr}`"
15
+ v-if="textarea"
16
+ density="comfortable"
17
+ rows="1"
18
+ :label="libelleInterieur ? $t(cleTradFr) : ''"
19
+ v-model="model[champs.Francais]"
20
+ :rules="reglesInterne"
21
+ :autofocus="autofocus && afficherChampFr"
22
+ />
23
+ <v-text-field
24
+ :id="`saisieChampFr-${cleTradFr}`"
25
+ v-else
26
+ density="comfortable"
27
+ :label="libelleInterieur ? $t(cleTradFr) : ''"
28
+ v-model="model[champs.Francais]"
29
+ :rules="reglesInterne"
30
+ :autofocus="autofocus && afficherChampFr"
31
+ />
32
+ </v-col>
33
+ <v-col
34
+ cols="12"
35
+ v-if="afficherChampEn"
36
+ >
37
+ <label
38
+ :for="`saisieChampEn-${cleTradEn}`"
39
+ :class="{ libelle: true, required: estRequis }"
40
+ v-if="!libelleInterieur"
41
+ >{{ $t(cleTradEn) }}</label
42
+ >
43
+ <v-textarea
44
+ :id="`saisieChampEn-${cleTradEn}`"
45
+ v-if="textarea"
46
+ rows="1"
47
+ density="comfortable"
48
+ :label="libelleInterieur ? $t(cleTradEn) : ''"
49
+ v-model="model[champs.Anglais]"
50
+ :rules="reglesInterne"
51
+ :autofocus="autofocus && !afficherChampFr"
52
+ />
53
+ <v-text-field
54
+ v-else
55
+ :id="`saisieChampEn-${cleTradEn}`"
56
+ density="comfortable"
57
+ :label="libelleInterieur ? $t(cleTradEn) : ''"
58
+ v-model="model[champs.Anglais]"
59
+ :rules="reglesInterne"
60
+ :autofocus="autofocus && !afficherChampFr"
61
+ />
62
+ </v-col>
63
+ </v-row>
64
+ </template>
65
+
66
+ <script setup lang="ts" generic="T extends { id: number }">
67
+ import {
68
+ estRequis as estRequisRegle,
69
+ estUniqueBilingue,
70
+ estMinimumLongueur,
71
+ estMaximumLongueur,
72
+ } from './../validateurs'
73
+
74
+ import { ChoixLangue } from '@/enums/choixLangue'
75
+ import { computed, type PropType, toRefs } from 'vue'
76
+
77
+ const props = defineProps<{
78
+ textarea?: boolean
79
+ libelleInterieur?: boolean
80
+ estRequis?: boolean
81
+ autofocus?: boolean
82
+ estUniqueValeurs?: T[]
83
+ minimumLongueur?: number
84
+ maximumLongueur?: number
85
+ regles?: Array<(v: string) => string | true>
86
+ langue: ChoixLangue
87
+ i18nLibelleRacine: string
88
+ champs: { ['Francais']: keyof T; ['Anglais']: keyof T }
89
+ }>()
90
+
91
+ const { textarea, libelleInterieur, autofocus, estUniqueValeurs, regles, langue, i18nLibelleRacine, champs } =
92
+ toRefs(props)
93
+
94
+ const minimumLongueur = computed(() => props.minimumLongueur)
95
+ const maximumLongueur = computed(() => props.maximumLongueur)
96
+ const estRequis = computed(() => props.estRequis)
97
+
98
+ const model = defineModel({
99
+ type: Object as PropType<T>,
100
+ required: true,
101
+ })
102
+
103
+ const reglesInterne = computed(() => {
104
+ const _regles: Array<(v: string) => string | true> = regles.value ?? []
105
+
106
+ if (minimumLongueur.value && maximumLongueur.value && minimumLongueur.value > maximumLongueur.value) {
107
+ console.error(
108
+ `CsqcTexteBilingue - Longueur min > max. (Min ${minimumLongueur.value} > Max ${maximumLongueur.value})`,
109
+ )
110
+ throw Error(
111
+ `CsqcTexteBilingue - Longueur min > max. (Min ${minimumLongueur.value} > Max ${maximumLongueur.value})`,
112
+ )
113
+ }
114
+
115
+ if (estRequis.value) _regles.push(v => estRequisRegle(v))
116
+
117
+ if (estUniqueValeurs.value) {
118
+ _regles.push(v =>
119
+ estUniqueBilingue(v, model.value, {
120
+ champs: { Anglais: champs.value.Anglais, Francais: champs.value.Francais },
121
+ valeurs: estUniqueValeurs.value!,
122
+ langueCss: langue.value,
123
+ }),
124
+ )
125
+ }
126
+
127
+ if (minimumLongueur.value !== undefined) _regles.push(v => estMinimumLongueur(v, minimumLongueur.value!))
128
+
129
+ if (maximumLongueur.value !== undefined) _regles.push(v => estMaximumLongueur(v, maximumLongueur.value!))
130
+
131
+ return _regles
132
+ })
133
+
134
+ // Clés i18n
135
+ const cleTradEn = computed(() => {
136
+ switch (langue.value) {
137
+ case ChoixLangue.Bilingue:
138
+ case ChoixLangue.Anglais:
139
+ return `${i18nLibelleRacine.value}.${String(champs.value.Anglais)}`
140
+ default:
141
+ return 'cle_manquante'
142
+ }
143
+ })
144
+
145
+ const cleTradFr = computed(() => {
146
+ switch (langue.value) {
147
+ case ChoixLangue.Bilingue:
148
+ case ChoixLangue.Francais:
149
+ return `${i18nLibelleRacine.value}.${String(champs.value.Francais)}`
150
+ default:
151
+ return 'cle_manquante'
152
+ }
153
+ })
154
+
155
+ const afficherChampFr = computed(() => langue.value === ChoixLangue.Francais || langue.value === ChoixLangue.Bilingue)
156
+ const afficherChampEn = computed(() => langue.value === ChoixLangue.Anglais || langue.value === ChoixLangue.Bilingue)
157
+ </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codevdesign",
3
- "version": "0.0.34",
3
+ "version": "0.0.36",
4
4
  "description": "Composants Vuetify 3 pour les projets Codev",
5
5
  "files": [
6
6
  "./**/*.vue",
package/validateurs.ts ADDED
@@ -0,0 +1,171 @@
1
+ import { ChoixLangue } from '@/enums/choixLangue'
2
+ // @ts-ignore
3
+ import i18n from '@/plugins/i18n.js'
4
+ const { t } = i18n.global
5
+
6
+ /**
7
+ * Valide que le champ contient une valeur définie et non vide.
8
+ * Accepte les chaînes de caractères non vides, les nombres différents de 0,
9
+ * et toute autre valeur définie (ex. objets sélectionnés dans un v-select).
10
+ *
11
+ * @param valeur La valeur saisie ou sélectionnée dans le champ.
12
+ * @returns `true` si la valeur est considérée comme valide, sinon retourne un message d'erreur.
13
+ */
14
+ export function estRequis(valeur: unknown): true | string {
15
+ if (valeur == null) return t('validateurs.estRequis')
16
+
17
+ if (typeof valeur === 'number' && isNaN(valeur)) return t('validateurs.estRequis')
18
+
19
+ if (typeof valeur === 'string') {
20
+ return valeur.trim().length > 0 || t('validateurs.estRequis')
21
+ }
22
+
23
+ return true // On considère tout le reste comme valide (ex: number, object, etc.)
24
+ }
25
+
26
+ /**
27
+ * Valide que le champ contient une valeur qui est d'une longeur minimale.
28
+ * @param valeur La valeur saisie du champ texte.
29
+ * @param min La longeur minimale de la valeur.
30
+ * @returns `true` si la longeur de la valeur est égale ou supérieure au minimum, sinon retourne un message d'erreur.
31
+ */
32
+ export function estMinimumLongueur(valeur: string, min: number) {
33
+ if (min <= 0) {
34
+ min = 1
35
+ console.warn(
36
+ 'CsqcValidateurs (estMinimumLongeur) - Une valeur négative ou égale à 0 a été reçue. Assurez-vous de passer une valeur supérieur à 0 dans la fonction estMinimumLongeur. La valeur a été mise à 1.',
37
+ )
38
+ }
39
+ return (valeur && valeur.trim().length >= min) || t('validateurs.estMinimumLongueur', { nbCaracteres: min }, min)
40
+ }
41
+
42
+ /**
43
+ * Valide que le champ contient une valeur qui ne dépasse pas une longeur maximale.
44
+ * @param valeur La valeur saisie du champ texte.
45
+ * @param max La longeur maximale (inclusive) de la valeur.
46
+ * @returns `true` si la longeur de la valeur est inférieure ou égale au maximum, sinon retourne un message d'erreur.
47
+ */
48
+ export function estMaximumLongueur(valeur: string, max: number) {
49
+ if (max < 1) {
50
+ max = 1
51
+ console.warn(
52
+ 'CsqcValidateurs (estMaximumLuongeur) - Une valeur négative ou égale à 0 a été reçue. Assurez-vous de passer une valeur supérieur à 0 dans la fonction estMaximumLongueur. La valeur a été mise à 1.',
53
+ )
54
+ }
55
+
56
+ return (valeur && valeur.trim().length <= max) || t('validateurs.estMaximumLongueur', { nbCaracteres: max }, max)
57
+ }
58
+
59
+ /**
60
+ * Vérifie qu'une valeur passée en paramètre est unique parmis une liste de valeurs. La validation du bilinguisme sera appliquée
61
+ * selon la langue CSS configurée et passée en option.
62
+ * @param valeur La valeur a vérifier
63
+ * @param modele L'instance d'un modèle avec un primary key id
64
+ * @param options Les configurations de la fonction
65
+ * @returns Vrai si la valeur est unique, ou une string d'erreur si un doublon est trouvé.
66
+ */
67
+ export function estUniqueBilingue<T extends ModeleAvecId>(
68
+ valeur: string,
69
+ modele: T,
70
+ options: EstUniqueOptionsBilingue<T>,
71
+ ) {
72
+ // Affectations valeurs par défaut
73
+ const { champs, langueCss, valeurs } = options
74
+ if (!langueCss) options.langueCss = ChoixLangue.Francais
75
+ valeur = valeur.toLowerCase().trim()
76
+
77
+ switch (langueCss) {
78
+ case ChoixLangue.Anglais:
79
+ if (!champs.Anglais) {
80
+ console.error(
81
+ 'CsqcValidateurs (estUnique) - Le champ anglais doit être speçifié lorsque la langueCss est en anglais.',
82
+ )
83
+ throw Error(
84
+ 'CsqcValidateurs (estUnique) - Le champ anglais doit être speçifié lorsque la langueCss est en anglais.',
85
+ )
86
+ }
87
+ return (
88
+ !valeurs.find(
89
+ e =>
90
+ (e[champs.Anglais!] as string) != null &&
91
+ (e[champs.Anglais!] as string).toLowerCase().trim() === valeur &&
92
+ e.id !== modele.id,
93
+ ) || t('validateurs.estUnique', { valeurExistante: valeur })
94
+ )
95
+ case ChoixLangue.Francais:
96
+ if (!champs.Francais) {
97
+ console.error(
98
+ 'CsqcValidateurs (estUnique) - Le champ français doit être speçifié lorsque la langueCss est en français.',
99
+ )
100
+ throw Error(
101
+ 'CsqcValidateurs (estUnique) - Le champ français doit être speçifié lorsque la langueCss est en français.',
102
+ )
103
+ }
104
+ return (
105
+ valeurs.find(
106
+ e =>
107
+ (e[champs.Francais!] as string) != null &&
108
+ (e[champs.Francais!] as string).toLowerCase().trim() === valeur &&
109
+ e.id !== modele.id,
110
+ ) == null || t('validateurs.estUnique', { valeurExistante: valeur })
111
+ )
112
+ case ChoixLangue.Bilingue:
113
+ if (!champs.Anglais || !champs.Francais) {
114
+ console.error(
115
+ "CsqcValidateurs (estUnique) - Les deux champs (français et anglais) doivent être speçifiés lorsque qu'on est en mode de validation bilingue.",
116
+ )
117
+ throw Error(
118
+ "CsqcValidateurs (estUnique) - Les deux champs (français et anglais) doivent être speçifiés lorsque qu'on est en mode de validation bilingue.",
119
+ )
120
+ }
121
+ const estUnique =
122
+ valeurs.find(
123
+ e =>
124
+ ((e[champs.Francais!] != null && (e[champs.Francais!] as string).toLowerCase().trim() === valeur) ||
125
+ (e[champs.Anglais!] != null && (e[champs.Anglais!] as string).toLowerCase().trim() === valeur)) &&
126
+ e.id !== modele.id,
127
+ ) == null
128
+ return estUnique || t('validateurs.estUnique', { valeurExistante: valeur })
129
+ default:
130
+ break
131
+ }
132
+
133
+ throw Error('pas supposé être ici')
134
+ }
135
+
136
+ /**
137
+ * Vérifie qu'une valeur passée en paramètre est unique parmis une liste de valeurs.
138
+ * @param valeur La valeur a vérifier
139
+ * @param modele L'instance d'un modèle avec un primary key id
140
+ * @param options Les configurations de la fonction
141
+ * @returns Vrai si la valeur est unique, ou une string d'erreur si un doublon est trouvé.
142
+ */
143
+ export function estUnique<T extends ModeleAvecId>(valeur: string, modele: T, options: EstUniqueOptions<T>) {
144
+ const { champ, valeurs } = options
145
+ return (
146
+ !valeurs.some(
147
+ e =>
148
+ e[champ] != null &&
149
+ (e[champ] as string).toLowerCase().trim() === valeur.toLowerCase().trim() &&
150
+ e.id !== modele.id,
151
+ ) || t('validateurs.estUnique', { valeurExistance: valeur })
152
+ )
153
+ }
154
+
155
+ type ModeleAvecId = { id: number }
156
+
157
+ type ValeursChampEstUniqueOptions<ModeleAvecId> = {
158
+ ['Francais']?: keyof ModeleAvecId
159
+ ['Anglais']?: keyof ModeleAvecId
160
+ }
161
+
162
+ interface EstUniqueOptionsBilingue<T extends ModeleAvecId> {
163
+ champs: ValeursChampEstUniqueOptions<T>
164
+ valeurs: T[]
165
+ langueCss?: ChoixLangue
166
+ }
167
+
168
+ interface EstUniqueOptions<T extends ModeleAvecId> {
169
+ champ: keyof T
170
+ valeurs: T[]
171
+ }