@cnamts/synapse 0.0.4-alpha → 0.0.5-alpha
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.
- package/dist/design-system-v3.d.ts +932 -224
- package/dist/design-system-v3.js +3374 -1502
- package/dist/design-system-v3.umd.cjs +6 -6
- package/dist/style.css +1 -1
- package/package.json +2 -1
- package/src/assets/tokens.scss +0 -1
- package/src/components/Alert/Accessibilite.mdx +14 -0
- package/src/components/Alert/Accessibilite.stories.ts +166 -0
- package/src/components/Alert/AccessibiliteItems.ts +152 -0
- package/src/components/Alert/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/BackBtn/Accessibilite.mdx +14 -0
- package/src/components/BackBtn/Accessibilite.stories.ts +166 -0
- package/src/components/BackBtn/AccessibiliteItems.ts +132 -0
- package/src/components/BackBtn/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/BackToTopBtn/Accessibilite.mdx +14 -0
- package/src/components/BackToTopBtn/Accessibilite.stories.ts +166 -0
- package/src/components/BackToTopBtn/AccessibiliteItems.ts +82 -0
- package/src/components/BackToTopBtn/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/CollapsibleList/Accessibilite.mdx +14 -0
- package/src/components/CollapsibleList/Accessibilite.stories.ts +166 -0
- package/src/components/CollapsibleList/AccessibiliteItems.ts +129 -0
- package/src/components/CollapsibleList/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/CopyBtn/Accessibilite.mdx +14 -0
- package/src/components/CopyBtn/Accessibilite.stories.ts +166 -0
- package/src/components/CopyBtn/AccessibiliteItems.ts +135 -0
- package/src/components/CopyBtn/config.ts +2 -0
- package/src/components/CopyBtn/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/Customs/SyBtnSelect/SyBtnSelect.mdx +44 -0
- package/src/components/Customs/SyBtnSelect/SyBtnSelect.stories.ts +606 -0
- package/src/components/Customs/SyBtnSelect/SyBtnSelect.vue +246 -0
- package/src/components/Customs/SyBtnSelect/tests/SyBtnSelect.spec.ts +168 -0
- package/src/components/Customs/SyInputSelect/SyInputSelect.mdx +40 -0
- package/src/components/Customs/{CustomInputSelect/CustomInputSelect.stories.ts → SyInputSelect/SyInputSelect.stories.ts} +29 -29
- package/src/components/Customs/{CustomInputSelect/CustomInputSelect.vue → SyInputSelect/SyInputSelect.vue} +10 -2
- package/src/components/Customs/SyInputSelect/tests/SyInputSelect.spec.ts +140 -0
- package/src/components/Customs/{CustomSelect/CustomSelect.mdx → SySelect/SySelect.mdx} +8 -8
- package/src/components/Customs/{CustomSelect/CustomSelect.stories.ts → SySelect/SySelect.stories.ts} +25 -25
- package/src/components/Customs/{CustomSelect/CustomSelect.vue → SySelect/SySelect.vue} +9 -5
- package/src/components/Customs/{CustomInputSelect/tests/CustomInputSelect.spec.ts → SySelect/tests/SySelect.spec.ts} +48 -71
- package/src/components/Customs/SyTextField/SyTextField.mdx +44 -0
- package/src/components/Customs/{CustomTextField/CustomTextField.stories.ts → SyTextField/SyTextField.stories.ts} +34 -34
- package/src/components/Customs/{CustomTextField/tests/CustomTextField.spec.ts → SyTextField/tests/SyTextField.spec.ts} +3 -3
- package/src/components/Customs/{CustomTextField/tests/__snapshots__/CustomTextField.spec.ts.snap → SyTextField/tests/__snapshots__/SyTextField.spec.ts.snap} +3 -5
- package/src/components/DialogBox/DialogBox.mdx +14 -0
- package/src/components/DialogBox/DialogBox.stories.ts +798 -0
- package/src/components/DialogBox/DialogBox.vue +181 -0
- package/src/components/DialogBox/config.ts +25 -0
- package/src/components/DialogBox/locales.ts +5 -0
- package/src/components/DialogBox/tests/DialogBox.spec.ts +329 -0
- package/src/components/DialogBox/tests/__snapshots__/DialogBox.spec.ts.snap +46 -0
- package/src/components/ErrorPage/ErrorPage.mdx +21 -0
- package/src/components/ErrorPage/ErrorPage.stories.ts +133 -0
- package/src/components/ErrorPage/ErrorPage.vue +93 -0
- package/src/components/ErrorPage/locales.ts +5 -0
- package/src/components/ErrorPage/tests/ErrorPage.spec.ts +40 -0
- package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +78 -0
- package/src/components/FooterBar/FooterBar.stories.ts +556 -8
- package/src/components/FooterBar/config.ts +2 -3
- package/src/components/FooterBar/tests/FooterBar.spec.ts +1 -1
- package/src/components/FooterBar/tests/FooterBarConfig.spec.ts +1 -1
- package/src/components/FooterBar/tests/__snapshots__/FooterBar.spec.ts.snap +2 -2
- package/src/components/FranceConnectBtn/Accessibilite.mdx +14 -0
- package/src/components/FranceConnectBtn/Accessibilite.stories.ts +194 -0
- package/src/components/FranceConnectBtn/AccessibiliteItems.ts +199 -0
- package/src/components/FranceConnectBtn/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/HeaderBar/HeaderBar.stories.ts +60 -2
- package/src/components/HeaderNavigationBar/HeaderNavigationBar.mdx +6 -6
- package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.spec.ts +1 -1
- package/src/components/HeaderToolbar/HeaderToolbar.vue +2 -2
- package/src/components/HeaderToolbar/tests/HeaderToolbar.spec.ts +36 -2
- package/src/components/LangBtn/Accessibilite.mdx +14 -0
- package/src/components/LangBtn/Accessibilite.stories.ts +166 -0
- package/src/components/LangBtn/AccessibiliteItems.ts +132 -0
- package/src/components/LangBtn/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/LangBtn/tests/LangBtn.spec.ts +1 -1
- package/src/components/LangBtn/tests/__snapshots__/LangBtn.spec.ts.snap +1 -1
- package/src/components/MaintenancePage/MaintenancePage.mdx +11 -0
- package/src/components/MaintenancePage/MaintenancePage.stories.ts +41 -0
- package/src/components/MaintenancePage/MaintenancePage.vue +25 -0
- package/src/components/MaintenancePage/assets/maintenance.svg +1 -0
- package/src/components/MaintenancePage/index.ts +3 -0
- package/src/components/MaintenancePage/locales.ts +5 -0
- package/src/components/MaintenancePage/tests/MaintenancePage.spec.ts +12 -0
- package/src/components/MaintenancePage/tests/__snapshots__/MaintenancePage.spec.ts.snap +3 -0
- package/src/components/NotFoundPage/NotFoundPage.mdx +19 -0
- package/src/components/NotFoundPage/NotFoundPage.stories.ts +76 -0
- package/src/components/NotFoundPage/NotFoundPage.vue +52 -0
- package/src/components/NotFoundPage/assets/not-found.svg +1 -0
- package/src/components/NotFoundPage/locales.ts +6 -0
- package/src/components/NotFoundPage/tests/NotFoundPage.spec.ts +38 -0
- package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +76 -0
- package/src/components/NotificationBar/Accessibilite.mdx +14 -0
- package/src/components/NotificationBar/Accessibilite.stories.ts +166 -0
- package/src/components/NotificationBar/AccessibiliteItems.ts +174 -0
- package/src/components/NotificationBar/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/NotificationBar/options.ts +1 -0
- package/src/components/PageContainer/Accessibilite.mdx +14 -0
- package/src/components/PageContainer/Accessibilite.stories.ts +166 -0
- package/src/components/PageContainer/AccessibiliteItems.ts +52 -0
- package/src/components/PageContainer/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/PhoneField/PhoneField.vue +5 -5
- package/src/components/PhoneField/tests/PhoneField.spec.ts +3 -3
- package/src/components/SkipLink/Accessibilite.mdx +14 -0
- package/src/components/SkipLink/Accessibilite.stories.ts +167 -0
- package/src/components/SkipLink/AccessibiliteItems.ts +77 -0
- package/src/components/SkipLink/constants/ExpertiseLevelEnum.ts +4 -0
- package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +17 -13
- package/src/components/SocialMediaLinks/SocialMediaLinks.stories.ts +2 -1
- package/src/components/SocialMediaLinks/tests/SocialMediaLinks.spec.ts +1 -1
- package/src/components/SocialMediaLinks/tests/__snapshots__/SocialMediaLinks.spec.ts.snap +2 -2
- package/src/components/SubHeader/SubHeader.vue +1 -1
- package/src/components/UserMenuBtn/UserMenuBtn.mdx +35 -0
- package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +438 -0
- package/src/components/UserMenuBtn/UserMenuBtn.vue +105 -0
- package/src/components/UserMenuBtn/config.ts +24 -0
- package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +125 -0
- package/src/components/index.ts +12 -3
- package/src/composables/index.ts +8 -0
- package/src/composables/rules/tests/useFieldValidation.spec.ts +82 -0
- package/src/composables/rules/useFieldValidation.ts +53 -0
- package/src/designTokens/index.ts +2 -0
- package/src/designTokens/tokens/cnam/cnamDarkTheme.ts +5 -0
- package/src/designTokens/tokens/cnam/cnamLightTheme.ts +1 -0
- package/src/main.ts +2 -0
- package/src/stories/Fondamentaux/Arrondis.mdx +24 -0
- package/src/stories/{Guidelines → Fondamentaux}/Colors.mdx +1 -1
- package/src/stories/Fondamentaux/Conteneurs.mdx +7 -0
- package/src/stories/Fondamentaux/CustomisationEtThemes.mdx +7 -0
- package/src/stories/Fondamentaux/Elevations.mdx +14 -0
- package/src/stories/Fondamentaux/Espacements.mdx +29 -0
- package/src/stories/{Guidelines → Fondamentaux}/Introduction.mdx +1 -1
- package/src/stories/Fondamentaux/StylesTypographiques.mdx +33 -0
- package/src/stories/Fondamentaux/Typographie.mdx +58 -0
- package/src/stories/GuideDuDev/CommentUtiliserLesRules.mdx +132 -0
- package/src/stories/{Fondamentaux → Guidelines}/Accessibilite/Accessibilite.stories.ts +1 -1
- package/src/stories/{Fondamentaux → Guidelines}/EcoConception/Econception.stories.ts +2 -2
- package/src/components/Customs/CustomInputSelect/CustomInputSelect.mdx +0 -40
- package/src/components/Customs/CustomSelect/tests/CustomSelect.spec.ts +0 -236
- package/src/components/Customs/CustomTextField/CustomTextField.mdx +0 -44
- package/src/stories/Guidelines/CustomisationEtThemes.mdx +0 -3
- package/src/stories/Guidelines/Typo.mdx +0 -53
- /package/src/components/Customs/{CustomInputSelect → SyInputSelect}/config.ts +0 -0
- /package/src/components/Customs/{CustomTextField/CustomTextField.vue → SyTextField/SyTextField.vue} +0 -0
- /package/src/components/Customs/{CustomTextField → SyTextField}/types.d.ts +0 -0
- /package/src/stories/{Fondamentaux → Guidelines}/Accessibilite/Accessibilite.mdx +0 -0
- /package/src/stories/{Fondamentaux → Guidelines}/Accessibilite/AccessibiliteItems.ts +0 -0
- /package/src/stories/{Fondamentaux → Guidelines}/Accessibilite/constants/ExpertiseLevelEnum.ts +0 -0
- /package/src/stories/{Fondamentaux → Guidelines}/Accessibilite/constants/RGAALevelEnum.ts +0 -0
- /package/src/stories/{Fondamentaux → Guidelines}/EcoConception/EcoConception.mdx +0 -0
- /package/src/stories/{Fondamentaux → Guidelines}/EcoConception/ecoDesignItems.ts +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { ref, watch, computed, onMounted, useSlots } from 'vue'
|
|
3
|
+
import { useDisplay } from 'vuetify'
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: {
|
|
7
|
+
type: [Object, String, null],
|
|
8
|
+
default: null,
|
|
9
|
+
},
|
|
10
|
+
menuItems: {
|
|
11
|
+
type: Array,
|
|
12
|
+
default: () => [],
|
|
13
|
+
},
|
|
14
|
+
label: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: 'Sélectionnez une option',
|
|
17
|
+
},
|
|
18
|
+
required: {
|
|
19
|
+
type: Boolean,
|
|
20
|
+
default: false,
|
|
21
|
+
},
|
|
22
|
+
menuId: {
|
|
23
|
+
type: String,
|
|
24
|
+
default: 'custom-btn-select-menu',
|
|
25
|
+
},
|
|
26
|
+
textKey: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: 'text',
|
|
29
|
+
},
|
|
30
|
+
valueKey: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: 'value',
|
|
33
|
+
},
|
|
34
|
+
primaryInfo: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: 'Information principale',
|
|
37
|
+
},
|
|
38
|
+
secondaryInfo: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: undefined,
|
|
41
|
+
},
|
|
42
|
+
hideIcon: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: false,
|
|
45
|
+
},
|
|
46
|
+
hideLogoutBtn: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
50
|
+
isMobileView: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: false,
|
|
53
|
+
},
|
|
54
|
+
iconOnly: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false,
|
|
57
|
+
},
|
|
58
|
+
options: {
|
|
59
|
+
type: Object,
|
|
60
|
+
default: () => ({ menu: {}, btn: {}, list: {} }),
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const emit = defineEmits(['update:modelValue', 'logout'])
|
|
65
|
+
const slots = useSlots()
|
|
66
|
+
const { smAndDown } = useDisplay()
|
|
67
|
+
|
|
68
|
+
const isOpen = ref(false)
|
|
69
|
+
const selectedItem = ref<Record<string, unknown> | string | null>(props.modelValue as Record<string, unknown> | string | null)
|
|
70
|
+
const toggleMenu = () => {
|
|
71
|
+
isOpen.value = !isOpen.value
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const buttonRef = ref<HTMLElement | null>(null)
|
|
75
|
+
const buttonWidth = ref('')
|
|
76
|
+
|
|
77
|
+
onMounted(() => {
|
|
78
|
+
if (buttonRef.value && !isMobileVersion.value) {
|
|
79
|
+
buttonWidth.value = `${buttonRef.value.getBoundingClientRect().width}px`
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const selectItem = (item: unknown) => {
|
|
84
|
+
selectedItem.value = item as string | Record<string, unknown> | null
|
|
85
|
+
emit('update:modelValue', item)
|
|
86
|
+
isOpen.value = false
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const getItemText = (item: unknown) => {
|
|
90
|
+
return (item as Record<string, unknown>)[props.textKey]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const formattedItems = computed(() => {
|
|
94
|
+
return props.menuItems.map((item) => {
|
|
95
|
+
if (typeof item === 'string') {
|
|
96
|
+
return { [props.textKey]: item, [props.valueKey]: item }
|
|
97
|
+
}
|
|
98
|
+
return item
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const btnPadding = computed(() => {
|
|
103
|
+
if (props.hideIcon) {
|
|
104
|
+
return 'pa-1 pa-sm-2'
|
|
105
|
+
}
|
|
106
|
+
return isMobileVersion.value ? 'pa-0' : 'pa-1 pa-sm-3'
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const hasListContent = computed(() => {
|
|
110
|
+
return Boolean(slots.default || !props.hideLogoutBtn)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const isMobileVersion = computed(() => {
|
|
114
|
+
return props.isMobileView || smAndDown.value || props.iconOnly
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
watch(() => props.modelValue, (newValue) => {
|
|
118
|
+
selectedItem.value = newValue
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const generatedId = ref(`custom-btn-select-${Math.random().toString(36).substring(7)}`)
|
|
122
|
+
|
|
123
|
+
defineExpose({
|
|
124
|
+
isOpen,
|
|
125
|
+
formattedItems,
|
|
126
|
+
selectedItem,
|
|
127
|
+
})
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
<template>
|
|
131
|
+
<div
|
|
132
|
+
ref="buttonRef"
|
|
133
|
+
class="vd-user-menu-btn-ctn d-inline-block"
|
|
134
|
+
>
|
|
135
|
+
<VMenu
|
|
136
|
+
:id="generatedId"
|
|
137
|
+
:disabled="!hasListContent"
|
|
138
|
+
location="bottom end"
|
|
139
|
+
transition="fade-transition"
|
|
140
|
+
v-bind="props.options['menu']"
|
|
141
|
+
z-index="9999"
|
|
142
|
+
>
|
|
143
|
+
<template #activator="{ props: menuProps }">
|
|
144
|
+
<VBtn
|
|
145
|
+
:id="generatedId"
|
|
146
|
+
:class="btnPadding"
|
|
147
|
+
:height="iconOnly ? 'auto' : undefined"
|
|
148
|
+
:width="iconOnly ? 'auto' : undefined"
|
|
149
|
+
:icon="iconOnly"
|
|
150
|
+
:size="iconOnly ? 'x-large' : 'default'"
|
|
151
|
+
class="vd-user-menu-btn"
|
|
152
|
+
v-bind="{
|
|
153
|
+
...menuProps,
|
|
154
|
+
...props.options['btn'],
|
|
155
|
+
}"
|
|
156
|
+
@click="toggleMenu"
|
|
157
|
+
>
|
|
158
|
+
<div
|
|
159
|
+
:class="['text-'+props?.options['btn']?.color]"
|
|
160
|
+
class="d-flex align-center"
|
|
161
|
+
>
|
|
162
|
+
<slot name="prepend-icon" />
|
|
163
|
+
<span class="d-sr-only">{{ props.label }}</span>
|
|
164
|
+
<span
|
|
165
|
+
v-if="!isMobileVersion && !iconOnly"
|
|
166
|
+
class="d-flex flex-column align-end py-1 mr-1"
|
|
167
|
+
>
|
|
168
|
+
<span
|
|
169
|
+
:class="`text-${props?.options['btn']?.textColor}`"
|
|
170
|
+
class="font-weight-bold"
|
|
171
|
+
>{{ props.primaryInfo }}
|
|
172
|
+
</span>
|
|
173
|
+
<span
|
|
174
|
+
:class="`text-${props?.options['btn']?.textColor}`"
|
|
175
|
+
class="text-grey text-darken-2 font-weight-medium"
|
|
176
|
+
>{{ props.secondaryInfo }}
|
|
177
|
+
</span>
|
|
178
|
+
</span>
|
|
179
|
+
<span
|
|
180
|
+
v-if="isMobileVersion && !iconOnly"
|
|
181
|
+
:class="`text-${props?.options['btn']?.textColor}`"
|
|
182
|
+
class="font-weight-bold text-caption"
|
|
183
|
+
>{{ props.primaryInfo }}</span>
|
|
184
|
+
<slot name="append-icon" />
|
|
185
|
+
</div>
|
|
186
|
+
</VBtn>
|
|
187
|
+
</template>
|
|
188
|
+
<slot name="content">
|
|
189
|
+
<VList
|
|
190
|
+
v-if="hasListContent"
|
|
191
|
+
v-bind="props.options['list']"
|
|
192
|
+
>
|
|
193
|
+
<VListItem
|
|
194
|
+
v-for="(item, index) in formattedItems"
|
|
195
|
+
:key="index"
|
|
196
|
+
:class="`text-${props?.options['list']?.textColor}`"
|
|
197
|
+
v-bind="props.options['list']"
|
|
198
|
+
@click="selectItem(item)"
|
|
199
|
+
>
|
|
200
|
+
<VListItemTitle v-bind="props.options['list']">
|
|
201
|
+
{{ getItemText(item) }}
|
|
202
|
+
</VListItemTitle>
|
|
203
|
+
</VListItem>
|
|
204
|
+
<slot />
|
|
205
|
+
<slot name="footer-list-item" />
|
|
206
|
+
</VList>
|
|
207
|
+
</slot>
|
|
208
|
+
</VMenu>
|
|
209
|
+
</div>
|
|
210
|
+
</template>
|
|
211
|
+
|
|
212
|
+
<style lang="scss" scoped>
|
|
213
|
+
@use '@/assets/tokens.scss';
|
|
214
|
+
|
|
215
|
+
.vd-user-menu-btn-ctn {
|
|
216
|
+
position: relative;
|
|
217
|
+
z-index: 1;
|
|
218
|
+
|
|
219
|
+
.v-btn.v-btn--density-default {
|
|
220
|
+
height: auto !important;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.vd-user-menu-btn {
|
|
225
|
+
outline: none;
|
|
226
|
+
padding: 12px !important;
|
|
227
|
+
|
|
228
|
+
&:hover:before {
|
|
229
|
+
background: #000;
|
|
230
|
+
opacity: 0.05;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
&:focus:before {
|
|
234
|
+
background: tokens.$blue-base;
|
|
235
|
+
opacity: 0.08;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
&:focus {
|
|
239
|
+
background: rgba(tokens.$blue-base, 0.08) !important;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
:deep(.vd-user-menu-btn:focus > .v-btn__overlay) {
|
|
244
|
+
opacity: 0 !important;
|
|
245
|
+
}
|
|
246
|
+
</style>
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import SyBtnSelect from '../SyBtnSelect.vue'
|
|
4
|
+
import { vuetify } from '@tests/unit/setup'
|
|
5
|
+
|
|
6
|
+
describe('SyBtnSelect', () => {
|
|
7
|
+
it('renders the component with default props', () => {
|
|
8
|
+
const wrapper = mount(SyBtnSelect, {
|
|
9
|
+
global: {
|
|
10
|
+
plugins: [vuetify],
|
|
11
|
+
},
|
|
12
|
+
props: {
|
|
13
|
+
primaryInfo: 'John Doe',
|
|
14
|
+
},
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
expect(wrapper.exists()).toBe(true)
|
|
18
|
+
expect(wrapper.text()).toContain('John Doe')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('shows secondaryInfo if provided', () => {
|
|
22
|
+
const wrapper = mount(SyBtnSelect, {
|
|
23
|
+
global: {
|
|
24
|
+
plugins: [vuetify],
|
|
25
|
+
},
|
|
26
|
+
props: {
|
|
27
|
+
primaryInfo: 'John Doe',
|
|
28
|
+
secondaryInfo: 'Additional Info',
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
expect(wrapper.text()).toContain('Additional Info')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('emits "update:modelValue" when an item is selected', async () => {
|
|
36
|
+
const wrapper = mount(SyBtnSelect, {
|
|
37
|
+
global: {
|
|
38
|
+
plugins: [vuetify],
|
|
39
|
+
},
|
|
40
|
+
props: {
|
|
41
|
+
modelValue: null,
|
|
42
|
+
menuItems: [
|
|
43
|
+
{ text: 'Option 1', value: 'option1' },
|
|
44
|
+
{ text: 'Option 2', value: 'option2' },
|
|
45
|
+
],
|
|
46
|
+
primaryInfo: 'John Doe',
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const button = wrapper.find('.vd-user-menu-btn')
|
|
51
|
+
await button.trigger('click')
|
|
52
|
+
|
|
53
|
+
expect(wrapper.vm.isOpen).toBe(true)
|
|
54
|
+
|
|
55
|
+
const listItem = wrapper.findAllComponents({ name: 'VListItem' }).at(0)
|
|
56
|
+
expect(listItem).toBeTruthy()
|
|
57
|
+
await listItem?.trigger('click')
|
|
58
|
+
|
|
59
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
60
|
+
expect(wrapper.emitted('update:modelValue')![0]).toEqual([
|
|
61
|
+
{ text: 'Option 1', value: 'option1' },
|
|
62
|
+
])
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('toggles the menu open and closed', async () => {
|
|
66
|
+
const wrapper = mount(SyBtnSelect, {
|
|
67
|
+
global: {
|
|
68
|
+
plugins: [vuetify],
|
|
69
|
+
},
|
|
70
|
+
props: {
|
|
71
|
+
primaryInfo: 'John Doe',
|
|
72
|
+
},
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const button = wrapper.find('.vd-user-menu-btn')
|
|
76
|
+
expect(wrapper.vm.isOpen).toBe(false)
|
|
77
|
+
|
|
78
|
+
await button.trigger('click')
|
|
79
|
+
expect(wrapper.vm.isOpen).toBe(true)
|
|
80
|
+
|
|
81
|
+
await button.trigger('click')
|
|
82
|
+
expect(wrapper.vm.isOpen).toBe(false)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('formats menu items correctly', () => {
|
|
86
|
+
const wrapper = mount(SyBtnSelect, {
|
|
87
|
+
global: {
|
|
88
|
+
plugins: [vuetify],
|
|
89
|
+
},
|
|
90
|
+
props: {
|
|
91
|
+
primaryInfo: 'John Doe',
|
|
92
|
+
menuItems: ['Option 1', 'Option 2'],
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const formattedItems = wrapper.vm.formattedItems
|
|
97
|
+
expect(formattedItems).toEqual([
|
|
98
|
+
{ text: 'Option 1', value: 'Option 1' },
|
|
99
|
+
{ text: 'Option 2', value: 'Option 2' },
|
|
100
|
+
])
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('updates selectedItem when modelValue changes', async () => {
|
|
104
|
+
const wrapper = mount(SyBtnSelect, {
|
|
105
|
+
global: {
|
|
106
|
+
plugins: [vuetify],
|
|
107
|
+
},
|
|
108
|
+
props: {
|
|
109
|
+
modelValue: 'initial-value',
|
|
110
|
+
primaryInfo: 'John Doe',
|
|
111
|
+
},
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
expect(wrapper.vm.selectedItem).toBe('initial-value')
|
|
115
|
+
|
|
116
|
+
await wrapper.setProps({ modelValue: 'new-value' })
|
|
117
|
+
expect(wrapper.vm.selectedItem).toBe('new-value')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('renders the primaryInfo in a span when isMobileVersion and hideIcon are true', async () => {
|
|
121
|
+
const wrapper = mount(SyBtnSelect, {
|
|
122
|
+
global: {
|
|
123
|
+
plugins: [vuetify],
|
|
124
|
+
},
|
|
125
|
+
props: {
|
|
126
|
+
primaryInfo: 'John Doe',
|
|
127
|
+
isMobileView: true,
|
|
128
|
+
hideIcon: true,
|
|
129
|
+
},
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
const span = wrapper.find('span.font-weight-bold.text-caption')
|
|
133
|
+
|
|
134
|
+
expect(span.text()).toBe('John Doe')
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('does not render the span if isMobileVersion is false', () => {
|
|
138
|
+
const wrapper = mount(SyBtnSelect, {
|
|
139
|
+
global: {
|
|
140
|
+
plugins: [vuetify],
|
|
141
|
+
},
|
|
142
|
+
props: {
|
|
143
|
+
primaryInfo: 'John Doe',
|
|
144
|
+
isMobileView: false,
|
|
145
|
+
hideIcon: true,
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const span = wrapper.find('span.font-weight-bold.text-sm-caption')
|
|
150
|
+
expect(span.exists()).toBe(false)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('does not render the span if hideIcon is false', () => {
|
|
154
|
+
const wrapper = mount(SyBtnSelect, {
|
|
155
|
+
global: {
|
|
156
|
+
plugins: [vuetify],
|
|
157
|
+
},
|
|
158
|
+
props: {
|
|
159
|
+
primaryInfo: 'John Doe',
|
|
160
|
+
isMobileView: true,
|
|
161
|
+
hideIcon: false,
|
|
162
|
+
},
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const span = wrapper.find('span.font-weight-bold.text-sm-caption')
|
|
166
|
+
expect(span.exists()).toBe(false)
|
|
167
|
+
})
|
|
168
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls, Story, Source } from '@storybook/blocks';
|
|
2
|
+
import * as SyInputSelectStories from "./SyInputSelect.stories";
|
|
3
|
+
|
|
4
|
+
<Meta of={SyInputSelectStories} />
|
|
5
|
+
|
|
6
|
+
# SyInputSelect
|
|
7
|
+
|
|
8
|
+
Le composant `SyInputSelect` est utilisé pour proposer une alternative au `v-select` de Vuetify qui ne respecte pas les règles RGAA.
|
|
9
|
+
|
|
10
|
+
<Canvas of={SyInputSelectStories.Default} />
|
|
11
|
+
|
|
12
|
+
<Story of={SyInputSelectStories.Info} />
|
|
13
|
+
|
|
14
|
+
# API
|
|
15
|
+
|
|
16
|
+
<Controls of={SyInputSelectStories.Default} />
|
|
17
|
+
|
|
18
|
+
# Exemple d'utilisation
|
|
19
|
+
|
|
20
|
+
<Source dark code={`
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import SyInputSelect from '@cnamts/synapse'
|
|
23
|
+
|
|
24
|
+
const items = [
|
|
25
|
+
{ text: 'Option 1', value: '1' },
|
|
26
|
+
{ text: 'Option 2', value: '2' },
|
|
27
|
+
],
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<main>
|
|
32
|
+
<div class="mt-12 ml-12">
|
|
33
|
+
<SyInputSelect
|
|
34
|
+
v-model="value"
|
|
35
|
+
:items="items"
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
</main>
|
|
39
|
+
</template>
|
|
40
|
+
`} />
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
-
import
|
|
2
|
+
import SyInputSelect from './SyInputSelect.vue'
|
|
3
3
|
import { VBtn, VMenu, VList, VListItem, VListItemTitle } from 'vuetify/components'
|
|
4
4
|
import { ref } from 'vue'
|
|
5
5
|
import Alert from '../../Alert/Alert.vue'
|
|
6
6
|
|
|
7
7
|
const meta = {
|
|
8
|
-
title: 'Composants/Formulaires/
|
|
9
|
-
component:
|
|
8
|
+
title: 'Composants/Formulaires/SyInputSelect',
|
|
9
|
+
component: SyInputSelect,
|
|
10
10
|
parameters: {
|
|
11
11
|
layout: 'fullscreen',
|
|
12
|
-
controls: { exclude: ['selectedValue'] },
|
|
12
|
+
controls: { exclude: ['selectedValue', 'isOpen', 'toggleMenu', 'closeList', 'selectItem', 'selectedItem', 'getItemText'] },
|
|
13
13
|
},
|
|
14
14
|
argTypes: {
|
|
15
15
|
selectedValue: { control: 'text' },
|
|
@@ -20,7 +20,7 @@ const meta = {
|
|
|
20
20
|
valueKey: { control: 'text' },
|
|
21
21
|
vuetifyOptions: { control: 'object' },
|
|
22
22
|
},
|
|
23
|
-
} as Meta<typeof
|
|
23
|
+
} as Meta<typeof SyInputSelect>
|
|
24
24
|
|
|
25
25
|
export default meta
|
|
26
26
|
|
|
@@ -32,7 +32,7 @@ export const Default: Story = {
|
|
|
32
32
|
name: 'Template',
|
|
33
33
|
code: `
|
|
34
34
|
<template>
|
|
35
|
-
<
|
|
35
|
+
<SyInputSelect
|
|
36
36
|
v-model="value"
|
|
37
37
|
:items="items"
|
|
38
38
|
/>
|
|
@@ -43,7 +43,7 @@ export const Default: Story = {
|
|
|
43
43
|
name: 'Script',
|
|
44
44
|
code: `
|
|
45
45
|
<script setup lang="ts">
|
|
46
|
-
import
|
|
46
|
+
import SyInputSelect from '@cnamts/SyInputSelect'
|
|
47
47
|
|
|
48
48
|
const items = [
|
|
49
49
|
{ text: 'Option 1', value: '1' },
|
|
@@ -70,13 +70,13 @@ export const Default: Story = {
|
|
|
70
70
|
},
|
|
71
71
|
render: (args) => {
|
|
72
72
|
return {
|
|
73
|
-
components: {
|
|
73
|
+
components: { SyInputSelect, VBtn, VMenu, VList, VListItem, VListItemTitle },
|
|
74
74
|
setup() {
|
|
75
75
|
return { args }
|
|
76
76
|
},
|
|
77
77
|
template: `
|
|
78
78
|
<div class="d-flex flex-wrap align-center pa-4">
|
|
79
|
-
<
|
|
79
|
+
<SyInputSelect
|
|
80
80
|
v-bind="args"
|
|
81
81
|
:vuetify-options="args.vuetifyOptions"
|
|
82
82
|
/>
|
|
@@ -94,7 +94,7 @@ export const Outlined: Story = {
|
|
|
94
94
|
name: 'Template',
|
|
95
95
|
code: `
|
|
96
96
|
<template>
|
|
97
|
-
<
|
|
97
|
+
<SyInputSelect
|
|
98
98
|
v-model="value"
|
|
99
99
|
:items="items"
|
|
100
100
|
outlined
|
|
@@ -106,7 +106,7 @@ export const Outlined: Story = {
|
|
|
106
106
|
name: 'Script',
|
|
107
107
|
code: `
|
|
108
108
|
<script setup lang="ts">
|
|
109
|
-
import
|
|
109
|
+
import SyInputSelect from '@cnamts/SyInputSelect'
|
|
110
110
|
|
|
111
111
|
const items = [
|
|
112
112
|
{ text: 'Option 1', value: '1' },
|
|
@@ -125,13 +125,13 @@ export const Outlined: Story = {
|
|
|
125
125
|
},
|
|
126
126
|
render: (args) => {
|
|
127
127
|
return {
|
|
128
|
-
components: {
|
|
128
|
+
components: { SyInputSelect, VBtn, VMenu, VList, VListItem, VListItemTitle },
|
|
129
129
|
setup() {
|
|
130
130
|
return { args }
|
|
131
131
|
},
|
|
132
132
|
template: `
|
|
133
133
|
<div class="d-flex flex-wrap align-center pa-4">
|
|
134
|
-
<
|
|
134
|
+
<SyInputSelect
|
|
135
135
|
v-bind="args"
|
|
136
136
|
outlined
|
|
137
137
|
/>
|
|
@@ -148,7 +148,7 @@ export const Required: Story = {
|
|
|
148
148
|
name: 'Template',
|
|
149
149
|
code: `
|
|
150
150
|
<template>
|
|
151
|
-
<
|
|
151
|
+
<SyInputSelect
|
|
152
152
|
v-model="value"
|
|
153
153
|
:items="items"
|
|
154
154
|
required
|
|
@@ -160,7 +160,7 @@ export const Required: Story = {
|
|
|
160
160
|
name: 'Script',
|
|
161
161
|
code: `
|
|
162
162
|
<script setup lang="ts">
|
|
163
|
-
import
|
|
163
|
+
import SyInputSelect from '@cnamts/SyInputSelect'
|
|
164
164
|
|
|
165
165
|
const items = [
|
|
166
166
|
{ text: 'Option 1', value: '1' },
|
|
@@ -180,13 +180,13 @@ export const Required: Story = {
|
|
|
180
180
|
},
|
|
181
181
|
render: (args) => {
|
|
182
182
|
return {
|
|
183
|
-
components: {
|
|
183
|
+
components: { SyInputSelect, VBtn, VMenu, VList, VListItem, VListItemTitle },
|
|
184
184
|
setup() {
|
|
185
185
|
return { args }
|
|
186
186
|
},
|
|
187
187
|
template: `
|
|
188
188
|
<div class="d-flex flex-wrap align-center pa-4">
|
|
189
|
-
<
|
|
189
|
+
<SyInputSelect
|
|
190
190
|
v-bind="args"
|
|
191
191
|
:required="args.required"
|
|
192
192
|
/>
|
|
@@ -203,7 +203,7 @@ export const withCustomError: Story = {
|
|
|
203
203
|
name: 'Template',
|
|
204
204
|
code: `
|
|
205
205
|
<template>
|
|
206
|
-
<
|
|
206
|
+
<SyInputSelect
|
|
207
207
|
v-model="value"
|
|
208
208
|
:items="items"
|
|
209
209
|
:error-messages="errorMessages"
|
|
@@ -218,7 +218,7 @@ export const withCustomError: Story = {
|
|
|
218
218
|
name: 'Script',
|
|
219
219
|
code: `
|
|
220
220
|
<script setup lang="ts">
|
|
221
|
-
import
|
|
221
|
+
import SyInputSelect from '@cnamts/SyInputSelect'
|
|
222
222
|
import { ref } from 'vue'
|
|
223
223
|
|
|
224
224
|
const items = [
|
|
@@ -244,7 +244,7 @@ export const withCustomError: Story = {
|
|
|
244
244
|
},
|
|
245
245
|
render: (args) => {
|
|
246
246
|
return {
|
|
247
|
-
components: {
|
|
247
|
+
components: { SyInputSelect, VBtn, VMenu, VList, VListItem, VListItemTitle },
|
|
248
248
|
setup() {
|
|
249
249
|
const errorMessages = ref([])
|
|
250
250
|
const triggerError = () => {
|
|
@@ -255,7 +255,7 @@ export const withCustomError: Story = {
|
|
|
255
255
|
},
|
|
256
256
|
template: `
|
|
257
257
|
<div class="d-flex flex-wrap align-center pa-4">
|
|
258
|
-
<
|
|
258
|
+
<SyInputSelect
|
|
259
259
|
v-bind="args"
|
|
260
260
|
:error-messages="errorMessages"
|
|
261
261
|
/>
|
|
@@ -275,7 +275,7 @@ export const withCustomKey: Story = {
|
|
|
275
275
|
name: 'Template',
|
|
276
276
|
code: `
|
|
277
277
|
<template>
|
|
278
|
-
<
|
|
278
|
+
<SyInputSelect
|
|
279
279
|
v-model="value"
|
|
280
280
|
:items="items"
|
|
281
281
|
text-key="customKey"
|
|
@@ -288,7 +288,7 @@ export const withCustomKey: Story = {
|
|
|
288
288
|
name: 'Script',
|
|
289
289
|
code: `
|
|
290
290
|
<script setup lang="ts">
|
|
291
|
-
import
|
|
291
|
+
import SyInputSelect from '@cnamts/SyInputSelect'
|
|
292
292
|
|
|
293
293
|
const items = [
|
|
294
294
|
{ customKey: 'Choix 1', value: '1' },
|
|
@@ -307,13 +307,13 @@ export const withCustomKey: Story = {
|
|
|
307
307
|
},
|
|
308
308
|
render: (args) => {
|
|
309
309
|
return {
|
|
310
|
-
components: {
|
|
310
|
+
components: { SyInputSelect, VBtn, VMenu, VList, VListItem, VListItemTitle },
|
|
311
311
|
setup() {
|
|
312
312
|
return { args }
|
|
313
313
|
},
|
|
314
314
|
template: `
|
|
315
315
|
<div class="d-flex flex-wrap align-center pa-4">
|
|
316
|
-
<
|
|
316
|
+
<SyInputSelect
|
|
317
317
|
v-bind="args"
|
|
318
318
|
outlined
|
|
319
319
|
text-key="customKey"
|
|
@@ -331,7 +331,7 @@ export const withCustomStyles: Story = {
|
|
|
331
331
|
name: 'Template',
|
|
332
332
|
code: `
|
|
333
333
|
<template>
|
|
334
|
-
<
|
|
334
|
+
<SyInputSelect
|
|
335
335
|
v-model="value"
|
|
336
336
|
:items="items"
|
|
337
337
|
:vuetify-options="vuetifyOptions
|
|
@@ -343,7 +343,7 @@ export const withCustomStyles: Story = {
|
|
|
343
343
|
name: 'Script',
|
|
344
344
|
code: `
|
|
345
345
|
<script setup lang="ts">
|
|
346
|
-
import
|
|
346
|
+
import SyInputSelect from '@cnamts/SyInputSelect'
|
|
347
347
|
|
|
348
348
|
const items = [
|
|
349
349
|
{ text: 'Option 1', value: '1' },
|
|
@@ -379,13 +379,13 @@ export const withCustomStyles: Story = {
|
|
|
379
379
|
},
|
|
380
380
|
render: (args) => {
|
|
381
381
|
return {
|
|
382
|
-
components: {
|
|
382
|
+
components: { SyInputSelect, VBtn, VMenu, VList, VListItem, VListItemTitle },
|
|
383
383
|
setup() {
|
|
384
384
|
return { args }
|
|
385
385
|
},
|
|
386
386
|
template: `
|
|
387
387
|
<div class="d-flex flex-wrap align-center pa-4">
|
|
388
|
-
<
|
|
388
|
+
<SyInputSelect
|
|
389
389
|
v-bind="args"
|
|
390
390
|
:items="args.items"
|
|
391
391
|
:vuetify-options="args.vuetifyOptions"
|