@cnamts/synapse 1.0.4 → 1.0.6
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/DateFilter-BlOpwEVq.js +98 -0
- package/dist/NumberFilter-BPUXE4wY.js +121 -0
- package/dist/PeriodFilter-B2yx329_.js +112 -0
- package/dist/SelectFilter-CedKn1oV.js +136 -0
- package/dist/TextFilter-DkhJjRtR.js +114 -0
- package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordion.d.ts +103 -0
- package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.d.ts +105 -0
- package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.d.ts +132 -0
- package/dist/components/Amelipro/AmeliproCaptcha/types.d.ts +5 -0
- package/dist/components/Amelipro/AmeliproCard/AmeliproCard.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.d.ts +126 -0
- package/dist/components/Amelipro/AmeliproCustomSelector/types.d.ts +6 -0
- package/dist/components/Amelipro/AmeliproIllustratedDataTile/AmeliproIllustratedDataTile.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproMultipleFoldingCard/AmeliproMultipleFoldingCard.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproTable/AmeliproTable.d.ts +190 -0
- package/dist/components/Amelipro/AmeliproTable/types.d.ts +34 -0
- package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +3 -3
- package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +1 -1
- package/dist/components/Amelipro/AmeliproTileBtn/AmeliproTileBtn.d.ts +1 -1
- package/dist/components/Amelipro/types.d.ts +6 -0
- package/dist/components/CookieBanner/CookieBanner.d.ts +1 -1
- package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +11 -2
- package/dist/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.d.ts +6 -1
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +3 -1
- package/dist/components/DataList/DataList.d.ts +9 -0
- package/dist/components/DataListGroup/DataListGroup.d.ts +10 -1
- package/dist/components/DataListItem/DataListItem.d.ts +1 -1
- package/dist/components/DataListItem/config.d.ts +1 -1
- package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +18 -8
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +16 -6
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +6 -1
- package/dist/components/DatePicker/composables/useDateInputEditing.d.ts +17 -8
- package/dist/components/DatePicker/composables/useKeyboardEvents.d.ts +41 -0
- package/dist/components/DatePicker/composables/useManualDateValidation.d.ts +4 -9
- package/dist/components/DatePicker/utils/dateFormattingUtils.d.ts +72 -0
- package/dist/components/DatePicker/utils/validationUtils.d.ts +38 -0
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.d.ts +9 -3
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.d.ts +6 -1
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.d.ts +11 -1
- package/dist/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.d.ts +11 -1
- package/dist/components/HeaderBar/HeaderBurgerMenu/locals.d.ts +2 -0
- package/dist/components/HeaderBar/HeaderBurgerMenu/useMenuPosition.d.ts +4 -0
- package/dist/components/NirField/NirField.d.ts +14 -4
- package/dist/components/PeriodField/PeriodField.d.ts +24 -4
- package/dist/components/Tables/common/SyTablePagination.d.ts +10 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/usePagination.d.ts +16 -0
- package/dist/design-system-v3.js +165 -160
- package/dist/design-system-v3.umd.cjs +120 -138
- package/dist/directives/lockFocus.d.ts +17 -0
- package/dist/{main-BzyNNvHX.js → main-BXPFSAB4.js} +14664 -13282
- package/dist/style.css +1 -0
- package/package.json +5 -2
- package/src/assets/amelipro/apTheme.scss +149 -0
- package/src/assets/amelipro/apTokens.scss +0 -148
- package/src/assets/overrides/_btns.scss +15 -0
- package/src/assets/overrides/_container.scss +36 -0
- package/src/assets/overrides/_forms.scss +7 -0
- package/src/assets/{_spacers.scss → overrides/_spacers.scss} +0 -7
- package/src/assets/overrides/_tables.scss +18 -0
- package/src/assets/overrides/_tooltips.scss +10 -0
- package/src/assets/overrides/_typography.scss +196 -0
- package/src/assets/settings.scss +11 -51
- package/src/assets/themes.scss +10 -0
- package/src/assets/tokens.scss +9 -156
- package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +80 -40
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.mdx +15 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.stories.ts +83 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.vue +86 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.vue +242 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/__tests__/AmeliproAccordionTemplate.spec.ts +20 -0
- package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/__tests__/__snapshots__/AmeliproAccordionTemplate.spec.ts.snap +124 -0
- package/src/components/Amelipro/AmeliproAccordion/__tests__/AmeliproAccordion.spec.ts +20 -0
- package/src/components/Amelipro/AmeliproAccordion/__tests__/__snapshots__/AmeliproAccordion.spec.ts.snap +124 -0
- package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.mdx +15 -0
- package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.stories.ts +87 -0
- package/src/components/Amelipro/AmeliproCaptcha/AmeliproCaptcha.vue +233 -0
- package/src/components/Amelipro/AmeliproCaptcha/__tests__/AmeliproCaptcha.spec.ts +24 -0
- package/src/components/Amelipro/AmeliproCaptcha/__tests__/__snapshots__/AmeliproCaptcha.spec.ts.snap +384 -0
- package/src/components/Amelipro/AmeliproCaptcha/types.d.ts +5 -0
- package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.mdx +15 -0
- package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.stories.ts +143 -0
- package/src/components/Amelipro/AmeliproCustomSelector/AmeliproCustomSelector.vue +351 -0
- package/src/components/Amelipro/AmeliproCustomSelector/__tests__/AmeliproCustomSelector.spec.ts +50 -0
- package/src/components/Amelipro/AmeliproCustomSelector/__tests__/__snapshots__/AmeliproCustomSelector.spec.ts.snap +186 -0
- package/src/components/Amelipro/AmeliproCustomSelector/types.d.ts +6 -0
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/tests/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/tests/__snapshots__/AmeliproHeaderBar.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproHeader/tests/__snapshots__/AmeliproHeader.spec.ts.snap +1 -708
- package/src/components/Amelipro/AmeliproMenu/tests/__snapshots__/AmeliproMenu.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproPageLayout/tests/__snapshots__/AmeliproPageLayout.spec.ts.snap +1 -708
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.mdx +22 -0
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.stories.ts +550 -0
- package/src/components/Amelipro/AmeliproTable/AmeliproTable.vue +421 -0
- package/src/components/Amelipro/AmeliproTable/__tests__/AmeliproTable.spec.ts +72 -0
- package/src/components/Amelipro/AmeliproTable/__tests__/__snapshots__/AmeliproTable.spec.ts.snap +427 -0
- package/src/components/Amelipro/AmeliproTable/types.d.ts +34 -0
- package/src/components/Amelipro/ServiceMenu/ServiceMenu.vue +12 -1
- package/src/components/Amelipro/ServiceMenu/tests/__snapshots__/ServiceMenu.spec.ts.snap +0 -820
- package/src/components/Amelipro/types.ts +8 -0
- package/src/components/CollapsibleList/CollapsibleList.vue +0 -2
- package/src/components/CookieBanner/CookieBanner.vue +1 -3
- package/src/components/CopyBtn/CopyBtn.vue +9 -2
- package/src/components/CopyBtn/tests/CopyBtn.spec.ts +3 -1
- package/src/components/Customs/Selects/SySelect/Accessibilite.mdx +7 -0
- package/src/components/Customs/Selects/SySelect/Accessibilite.stories.ts +4 -1
- package/src/components/Customs/Selects/SySelect/SySelect.stories.ts +80 -0
- package/src/components/Customs/Selects/SySelect/SySelect.vue +280 -34
- package/src/components/Customs/Selects/SySelect/composables/tests/useSySelectKeyboard.spec.ts +14 -5
- package/src/components/Customs/Selects/SySelect/composables/useSySelectKeyboard.ts +129 -12
- package/src/components/Customs/SyIcon/SyIcon.spec.ts +3 -0
- package/src/components/Customs/SyTextField/Accessibilite.stories.ts +3 -1
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +79 -6
- package/src/components/Customs/SyTextField/SyTextField.vue +218 -24
- package/src/components/DataList/Accessibilite.stories.ts +4 -0
- package/src/components/DataList/DataList.vue +19 -12
- package/src/components/DataListGroup/Accessibilite.stories.ts +4 -0
- package/src/components/DataListGroup/DataListGroup.vue +32 -15
- package/src/components/DataListItem/DataListItem.vue +14 -11
- package/src/components/DataListItem/config.ts +1 -1
- package/src/components/DataListItem/tests/DataListItem.spec.ts +2 -2
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +12 -7
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +174 -0
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +27 -5
- package/src/components/DatePicker/DatePickerValidationExample/DatePickerValidation.stories.ts +286 -0
- package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +1 -1
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +29 -31
- package/src/components/DatePicker/composables/tests/useManualDateValidation.spec.ts +11 -3
- package/src/components/DatePicker/composables/useDateInputEditing.ts +73 -209
- package/src/components/DatePicker/composables/useKeyboardEvents.ts +149 -0
- package/src/components/DatePicker/composables/useManualDateValidation.ts +27 -68
- package/src/components/DatePicker/utils/dateFormattingUtils.ts +228 -0
- package/src/components/DatePicker/utils/validationUtils.ts +90 -0
- package/src/components/DialogBox/Accessibilite.stories.ts +4 -0
- package/src/components/DialogBox/DialogBox.stories.ts +10 -10
- package/src/components/DialogBox/DialogBox.vue +83 -21
- package/src/components/DialogBox/tests/__snapshots__/DialogBox.spec.ts.snap +12 -6
- package/src/components/FileUpload/tests/FileUpload.spec.ts +3 -0
- package/src/components/FooterBar/FooterBar.vue +1 -0
- package/src/components/HeaderBar/Accessibilite.stories.ts +4 -0
- package/src/components/HeaderBar/HeaderBar.mdx +47 -22
- package/src/components/HeaderBar/HeaderBar.stories.ts +54 -13
- package/src/components/HeaderBar/HeaderBar.vue +2 -1
- package/src/components/HeaderBar/HeaderBurgerMenu/Accessibilite.stories.ts +4 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.stories.ts +160 -82
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderBurgerMenu.vue +41 -56
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuItem/HeaderMenuItem.vue +10 -3
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/HeaderMenuSection.vue +41 -18
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderMenuSection/tests/HeaderMenuSection.spec.ts +7 -2
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +36 -9
- package/src/components/HeaderBar/HeaderBurgerMenu/HeaderSubMenu/HeaderSubMenu.vue +41 -9
- package/src/components/HeaderBar/HeaderBurgerMenu/locals.ts +2 -0
- package/src/components/HeaderBar/HeaderBurgerMenu/tests/HeaderBurgerMenu.spec.ts +1 -1
- package/src/components/HeaderBar/HeaderBurgerMenu/tests/__snapshots__/HeaderBurgerMenu.spec.ts.snap +8 -3
- package/src/components/HeaderBar/HeaderBurgerMenu/useMenuPosition.ts +50 -0
- package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +5 -5
- package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +7 -4
- package/src/components/HeaderBar/locales.ts +1 -1
- package/src/components/HeaderBar/tests/__snapshots__/HeaderBar.spec.ts.snap +2 -1
- package/src/components/HeaderLoading/HeaderLoading.vue +0 -1
- package/src/components/HeaderNavigationBar/tests/HeaderNavigationBar.spec.ts +2 -0
- package/src/components/LangBtn/LangBtn.vue +0 -3
- package/src/components/LogoBrandSection/Accessibilite.stories.ts +4 -1
- package/src/components/LogoBrandSection/LogoBrandSection.stories.ts +2 -2
- package/src/components/LogoBrandSection/LogoBrandSection.vue +13 -8
- package/src/components/LogoBrandSection/locales.ts +1 -1
- package/src/components/LogoBrandSection/tests/LogoBrandSection.spec.ts +1 -1
- package/src/components/LogoBrandSection/tests/__snapshots__/LogoBrandSection.spec.ts.snap +6 -4
- package/src/components/NirField/NirField.vue +5 -5
- package/src/components/NirField/tests/NirField.spec.ts +78 -12
- package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +104 -6
- package/src/components/Tables/common/TableHeader.vue +10 -7
- package/src/components/Tables/common/tableAccessibilityUtils.ts +13 -2
- package/src/components/Tables/common/useTableAria.ts +17 -1
- package/src/components/UserMenuBtn/tests/UserMenuBtn.spec.ts +2 -1
- package/src/components/index.ts +4 -0
- package/src/composables/date/tests/useDatePickerAccessibility.spec.ts +34 -5
- package/src/composables/index.ts +3 -0
- package/src/composables/useFilterable/useFilterable.ts +13 -1
- package/src/composables/usePagination.ts +103 -0
- package/src/directives/lockFocus.ts +48 -0
- package/src/main.ts +1 -2
- package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +1 -8
- package/src/stories/Accessibilite/{Aculturation/AuditDesignSystem.mdx → AuditDesignSystem.mdx} +1 -1
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.mdx +102 -0
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru/FauxPositifs.stories.ts +219 -0
- package/src/stories/Accessibilite/KitDePreAudit/Outils/{Tanaguru.mdx → Tanaguru/Utilisation.mdx} +1 -1
- package/src/stories/DesignTokens/ColorIntegrationExample.vue +43 -0
- package/src/stories/DesignTokens/Colors.mdx +2 -0
- package/src/stories/DesignTokens/colors.stories.ts +9 -0
- package/src/vuetifyConfig.ts +3 -3
- package/dist/DateFilter-yrwJv_2R.js +0 -95
- package/dist/NumberFilter-BQXtywZI.js +0 -117
- package/dist/PeriodFilter-BYXVSzr5.js +0 -108
- package/dist/SelectFilter-CJV_mlN3.js +0 -133
- package/dist/TextFilter-DN0ejYIs.js +0 -110
- package/dist/design-system-v3.css +0 -1
- package/dist/directives/letterSpacing.d.ts +0 -27
- package/src/assets/_fonts.scss +0 -6
- package/src/assets/_typography.scss +0 -157
- package/src/directives/letterSpacing.ts +0 -233
- /package/src/assets/{_elevations.scss → overrides/_elevations.scss} +0 -0
- /package/src/assets/{_radius.scss → overrides/_radius.scss} +0 -0
package/src/components/Customs/Selects/SySelect/composables/tests/useSySelectKeyboard.spec.ts
CHANGED
|
@@ -191,7 +191,7 @@ describe('useSySelectKeyboard', () => {
|
|
|
191
191
|
})
|
|
192
192
|
|
|
193
193
|
describe('handleUpKey', () => {
|
|
194
|
-
it('ouvre le menu et sélectionne le
|
|
194
|
+
it('ouvre le menu et sélectionne le premier élément si le menu est fermé (comportement RGAA)', async () => {
|
|
195
195
|
isOpen.value = false
|
|
196
196
|
keyboard.handleUpKey()
|
|
197
197
|
expect(toggleMenu).toHaveBeenCalled()
|
|
@@ -200,7 +200,8 @@ describe('useSySelectKeyboard', () => {
|
|
|
200
200
|
isOpen.value = true
|
|
201
201
|
await nextTick()
|
|
202
202
|
|
|
203
|
-
|
|
203
|
+
// Comportement RGAA correct : flèche haut ouvre et va au premier élément
|
|
204
|
+
expect(keyboard.activeDescendantId.value).toBe('option-0')
|
|
204
205
|
})
|
|
205
206
|
|
|
206
207
|
it('sélectionne l\'élément précédent si le menu est ouvert', () => {
|
|
@@ -210,24 +211,32 @@ describe('useSySelectKeyboard', () => {
|
|
|
210
211
|
expect(keyboard.activeDescendantId.value).toBe('option-1')
|
|
211
212
|
})
|
|
212
213
|
|
|
213
|
-
it('
|
|
214
|
+
it('reste au premier élément si on est déjà au premier (pas de bouclage)', () => {
|
|
214
215
|
isOpen.value = true
|
|
215
216
|
keyboard.setActiveDescendant(0)
|
|
216
217
|
keyboard.handleUpKey()
|
|
217
|
-
|
|
218
|
+
// Ne doit pas boucler, doit rester au premier élément
|
|
219
|
+
expect(keyboard.activeDescendantId.value).toBe('option-0')
|
|
218
220
|
})
|
|
219
221
|
})
|
|
220
222
|
|
|
221
223
|
describe('handleCharacterKey', () => {
|
|
222
224
|
it('trouve et sélectionne un élément commençant par le caractère donné', () => {
|
|
225
|
+
// Menu déjà ouvert, pas besoin d'attendre nextTick
|
|
226
|
+
isOpen.value = true
|
|
223
227
|
keyboard.handleCharacterKey('b')
|
|
224
228
|
expect(keyboard.activeDescendantId.value).toBe('option-1') // Banana
|
|
225
229
|
})
|
|
226
230
|
|
|
227
|
-
it('ouvre le menu si fermé et trouve un élément correspondant', () => {
|
|
231
|
+
it('ouvre le menu si fermé et trouve un élément correspondant', async () => {
|
|
228
232
|
isOpen.value = false
|
|
229
233
|
keyboard.handleCharacterKey('c')
|
|
230
234
|
expect(toggleMenu).toHaveBeenCalled()
|
|
235
|
+
|
|
236
|
+
// Simuler l'ouverture du menu et attendre nextTick
|
|
237
|
+
isOpen.value = true
|
|
238
|
+
await nextTick()
|
|
239
|
+
|
|
231
240
|
expect(keyboard.activeDescendantId.value).toBe('option-2') // Cherry
|
|
232
241
|
})
|
|
233
242
|
|
|
@@ -7,7 +7,7 @@ export type ItemType = {
|
|
|
7
7
|
export interface UseSySelectKeyboardOptions {
|
|
8
8
|
isOpen: Ref<boolean>
|
|
9
9
|
formattedItems: Ref<ItemType[]>
|
|
10
|
-
toggleMenu: () => void
|
|
10
|
+
toggleMenu: (skipInitialFocus?: boolean) => void
|
|
11
11
|
selectItem: (item: ItemType | null, event?: Event) => void
|
|
12
12
|
getItemText: (item: unknown) => unknown
|
|
13
13
|
updateListPosition: () => void
|
|
@@ -85,6 +85,22 @@ export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
|
|
|
85
85
|
})
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Fonction pour effacer seulement le focus visuel et ARIA sans réinitialiser lastFocusedIndex
|
|
90
|
+
* Utilisée quand on ferme le dropdown mais qu'on veut conserver la mémoire du dernier focus
|
|
91
|
+
*/
|
|
92
|
+
const clearVisualFocus = () => {
|
|
93
|
+
activeDescendantId.value = ''
|
|
94
|
+
|
|
95
|
+
// Supprimer la classe de focus visuel de tous les éléments
|
|
96
|
+
nextTick(() => {
|
|
97
|
+
const allItems = document.querySelectorAll('.v-list-item')
|
|
98
|
+
allItems.forEach((item) => {
|
|
99
|
+
item.classList.remove('keyboard-focused')
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
88
104
|
/**
|
|
89
105
|
* Trouve l'index de l'élément actuellement sélectionné ou actif
|
|
90
106
|
* Utilise lastFocusedIndex comme source de vérité principale
|
|
@@ -171,29 +187,37 @@ export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
|
|
|
171
187
|
|
|
172
188
|
const handleDownKey = () => {
|
|
173
189
|
if (!isOpen.value) {
|
|
174
|
-
toggleMenu
|
|
190
|
+
// Passer skipInitialFocus=true pour éviter que toggleMenu override notre focus
|
|
191
|
+
toggleMenu(true)
|
|
175
192
|
nextTick(() => {
|
|
176
|
-
//
|
|
177
|
-
|
|
193
|
+
// Restaurer le dernier item qui avait le focus, ou le premier item par défaut
|
|
194
|
+
const indexToFocus = lastFocusedIndex.value >= 0 && lastFocusedIndex.value < formattedItems.value.length
|
|
195
|
+
? lastFocusedIndex.value
|
|
196
|
+
: 0
|
|
197
|
+
setActiveDescendant(indexToFocus)
|
|
178
198
|
})
|
|
179
199
|
}
|
|
180
200
|
else {
|
|
181
|
-
|
|
182
|
-
const
|
|
201
|
+
// Utiliser lastFocusedIndex comme point de départ (pas l'item sélectionné)
|
|
202
|
+
const currentIndex = lastFocusedIndex.value >= 0 ? lastFocusedIndex.value : 0
|
|
203
|
+
const nextIndex = Math.min(currentIndex + 1, formattedItems.value.length - 1)
|
|
183
204
|
setActiveDescendant(nextIndex)
|
|
184
205
|
}
|
|
185
206
|
}
|
|
186
207
|
|
|
187
208
|
const handleUpKey = () => {
|
|
188
209
|
if (!isOpen.value) {
|
|
189
|
-
toggleMenu
|
|
210
|
+
// Passer skipInitialFocus=true pour éviter que toggleMenu override notre focus
|
|
211
|
+
toggleMenu(true)
|
|
190
212
|
nextTick(() => {
|
|
191
|
-
|
|
213
|
+
// Aller au premier item quand on ouvre avec flèche haut (comportement RGAA correct)
|
|
214
|
+
setActiveDescendant(0)
|
|
192
215
|
})
|
|
193
216
|
}
|
|
194
217
|
else {
|
|
195
218
|
const currentIndex = findSelectedItemIndex()
|
|
196
|
-
|
|
219
|
+
// Ne pas boucler : rester au premier item si on est déjà au premier
|
|
220
|
+
const prevIndex = currentIndex >= 0 ? Math.max(currentIndex - 1, 0) : 0
|
|
197
221
|
setActiveDescendant(prevIndex)
|
|
198
222
|
}
|
|
199
223
|
}
|
|
@@ -203,12 +227,100 @@ export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
|
|
|
203
227
|
if (key.length === 1 && key.match(/\S/)) {
|
|
204
228
|
const index = findItemStartingWith(key)
|
|
205
229
|
if (index >= 0) {
|
|
206
|
-
if (!isOpen.value)
|
|
207
|
-
|
|
230
|
+
if (!isOpen.value) {
|
|
231
|
+
toggleMenu()
|
|
232
|
+
// Attendre que le menu soit ouvert avant de définir le focus
|
|
233
|
+
nextTick(() => {
|
|
234
|
+
setActiveDescendant(index)
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
// Menu déjà ouvert, définir le focus immédiatement
|
|
239
|
+
setActiveDescendant(index)
|
|
240
|
+
}
|
|
208
241
|
}
|
|
209
242
|
}
|
|
210
243
|
}
|
|
211
244
|
|
|
245
|
+
const handleHomeKey = () => {
|
|
246
|
+
if (!isOpen.value) {
|
|
247
|
+
toggleMenu()
|
|
248
|
+
nextTick(() => {
|
|
249
|
+
// Aller au premier item
|
|
250
|
+
setActiveDescendant(0)
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// Menu déjà ouvert, aller au premier item
|
|
255
|
+
setActiveDescendant(0)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const handleEndKey = () => {
|
|
260
|
+
if (!isOpen.value) {
|
|
261
|
+
toggleMenu()
|
|
262
|
+
nextTick(() => {
|
|
263
|
+
// Aller au dernier item
|
|
264
|
+
setActiveDescendant(formattedItems.value.length - 1)
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
// Menu déjà ouvert, aller au dernier item
|
|
269
|
+
setActiveDescendant(formattedItems.value.length - 1)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const handlePageUpKey = () => {
|
|
274
|
+
if (!isOpen.value) {
|
|
275
|
+
toggleMenu()
|
|
276
|
+
nextTick(() => {
|
|
277
|
+
// Aller au premier item
|
|
278
|
+
setActiveDescendant(0)
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Menu déjà ouvert, naviguer de 10 items vers le haut
|
|
283
|
+
const currentIndex = lastFocusedIndex.value >= 0 ? lastFocusedIndex.value : 0
|
|
284
|
+
const newIndex = Math.max(currentIndex - 10, 0)
|
|
285
|
+
setActiveDescendant(newIndex)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const handlePageDownKey = () => {
|
|
290
|
+
if (!isOpen.value) {
|
|
291
|
+
toggleMenu()
|
|
292
|
+
nextTick(() => {
|
|
293
|
+
// Aller au dernier item
|
|
294
|
+
setActiveDescendant(formattedItems.value.length - 1)
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
// Menu déjà ouvert, naviguer de 10 items vers le bas
|
|
299
|
+
const currentIndex = lastFocusedIndex.value >= 0 ? lastFocusedIndex.value : 0
|
|
300
|
+
const newIndex = Math.min(currentIndex + 10, formattedItems.value.length - 1)
|
|
301
|
+
setActiveDescendant(newIndex)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const handleTabKey = () => {
|
|
306
|
+
if (isOpen.value && activeDescendantId.value) {
|
|
307
|
+
// Trouver l'item actuellement focusé
|
|
308
|
+
const currentIndex = parseInt(activeDescendantId.value.split('-')[1])
|
|
309
|
+
if (!isNaN(currentIndex) && currentIndex >= 0 && currentIndex < formattedItems.value.length) {
|
|
310
|
+
const currentItem = formattedItems.value[currentIndex]
|
|
311
|
+
// Sélectionner l'item qui a le focus
|
|
312
|
+
selectItem(currentItem)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Fermer le menu (la navigation Tab normale continuera après)
|
|
316
|
+
if (isOpen.value) {
|
|
317
|
+
isOpen.value = false
|
|
318
|
+
clearActiveDescendant()
|
|
319
|
+
}
|
|
320
|
+
// Ne pas empêcher le comportement par défaut de Tab pour permettre
|
|
321
|
+
// la navigation vers l'élément suivant focusable
|
|
322
|
+
}
|
|
323
|
+
|
|
212
324
|
// Watch activeDescendantId pour synchroniser lastFocusedIndex
|
|
213
325
|
watch(activeDescendantId, (newId) => {
|
|
214
326
|
if (newId) {
|
|
@@ -240,7 +352,7 @@ export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
|
|
|
240
352
|
}
|
|
241
353
|
else {
|
|
242
354
|
// Conserver lastFocusedIndex mais effacer le focus visuel et ARIA
|
|
243
|
-
|
|
355
|
+
clearVisualFocus()
|
|
244
356
|
}
|
|
245
357
|
})
|
|
246
358
|
|
|
@@ -267,6 +379,11 @@ export function useSySelectKeyboard(options: UseSySelectKeyboardOptions) {
|
|
|
267
379
|
handleUpKey,
|
|
268
380
|
handleCharacterKey,
|
|
269
381
|
handleEscapeKey,
|
|
382
|
+
handleHomeKey,
|
|
383
|
+
handleEndKey,
|
|
384
|
+
handlePageUpKey,
|
|
385
|
+
handlePageDownKey,
|
|
386
|
+
handleTabKey,
|
|
270
387
|
restoreFocus,
|
|
271
388
|
}
|
|
272
389
|
}
|
|
@@ -8,6 +8,7 @@ describe('SyIcon', () => {
|
|
|
8
8
|
const wrapper = mount(SyIcon, {
|
|
9
9
|
props: {
|
|
10
10
|
icon: 'mdi-home',
|
|
11
|
+
decorative: true, // Marquer l'icône comme décorative pour éviter les avertissements d'accessibilité
|
|
11
12
|
},
|
|
12
13
|
global: {
|
|
13
14
|
stubs: {
|
|
@@ -82,6 +83,7 @@ describe('SyIcon', () => {
|
|
|
82
83
|
const wrapper = mount(SyIcon, {
|
|
83
84
|
props: {
|
|
84
85
|
icon: 'mdi-home',
|
|
86
|
+
decorative: true, // Marquer l'icône comme décorative pour éviter les avertissements d'accessibilité
|
|
85
87
|
color: 'primary',
|
|
86
88
|
},
|
|
87
89
|
global: {
|
|
@@ -106,6 +108,7 @@ describe('SyIcon', () => {
|
|
|
106
108
|
const wrapper = mount(SyIcon, {
|
|
107
109
|
props: {
|
|
108
110
|
icon: 'mdi-home',
|
|
111
|
+
decorative: true, // Marquer l'icône comme décorative pour éviter les avertissements d'accessibilité
|
|
109
112
|
size: 'large',
|
|
110
113
|
},
|
|
111
114
|
global: {
|
|
@@ -222,7 +222,9 @@ export const Legende: StoryObj = {
|
|
|
222
222
|
rapport</a></p>
|
|
223
223
|
<p style="color: grey; font-size: 14px">Correctifs associés (<a
|
|
224
224
|
href="https://github.com/assurance-maladie-digital/design-system/issues/4028" target="_blank"
|
|
225
|
-
style="color:#0C41BD;">issue #4028</a
|
|
225
|
+
style="color:#0C41BD;">issue #4028</a>, <a
|
|
226
|
+
href="https://github.com/assurance-maladie-digital/design-system-v3/pull/935" target="_blank"
|
|
227
|
+
style="color:#0C41BD;">issue #935</a>)</p>
|
|
226
228
|
</div>
|
|
227
229
|
`,
|
|
228
230
|
}
|
|
@@ -181,6 +181,10 @@ const meta = {
|
|
|
181
181
|
description: 'Texte d\'aide affiché sous le champ',
|
|
182
182
|
control: 'text',
|
|
183
183
|
},
|
|
184
|
+
'helpText': {
|
|
185
|
+
description: 'Texte d\'aide affiché sous le champ',
|
|
186
|
+
control: 'text',
|
|
187
|
+
},
|
|
184
188
|
'loading': {
|
|
185
189
|
description: 'Affiche un indicateur de chargement',
|
|
186
190
|
control: 'boolean',
|
|
@@ -377,6 +381,58 @@ export const Default: Story = {
|
|
|
377
381
|
},
|
|
378
382
|
}
|
|
379
383
|
|
|
384
|
+
export const HelpText: Story = {
|
|
385
|
+
parameters: {
|
|
386
|
+
sourceCode: [
|
|
387
|
+
{
|
|
388
|
+
name: 'Template',
|
|
389
|
+
code: `
|
|
390
|
+
<template>
|
|
391
|
+
<SyTextField
|
|
392
|
+
v-model="value"
|
|
393
|
+
help-text="Texte d'aide à la saisie"
|
|
394
|
+
/>
|
|
395
|
+
</template>
|
|
396
|
+
`,
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: 'Script',
|
|
400
|
+
code: `
|
|
401
|
+
<script setup lang="ts">
|
|
402
|
+
import { SyTextField } from '@cnamts/synapse'
|
|
403
|
+
</script>
|
|
404
|
+
`,
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
},
|
|
408
|
+
args: {
|
|
409
|
+
showDivider: false,
|
|
410
|
+
variantStyle: 'outlined',
|
|
411
|
+
color: 'primary',
|
|
412
|
+
isClearable: true,
|
|
413
|
+
label: 'Label',
|
|
414
|
+
modelValue: '',
|
|
415
|
+
helpText: 'Texte d\'aide à la saisie',
|
|
416
|
+
},
|
|
417
|
+
render: (args) => {
|
|
418
|
+
return {
|
|
419
|
+
components: { SyTextField, VIcon },
|
|
420
|
+
setup() {
|
|
421
|
+
const value = ref(args.modelValue)
|
|
422
|
+
watch(() => args.modelValue, (newValue) => {
|
|
423
|
+
value.value = newValue
|
|
424
|
+
})
|
|
425
|
+
return { args, value }
|
|
426
|
+
},
|
|
427
|
+
template: `
|
|
428
|
+
<div>
|
|
429
|
+
<SyTextField v-bind="args" v-model="value" />
|
|
430
|
+
</div>
|
|
431
|
+
`,
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
}
|
|
435
|
+
|
|
380
436
|
export const Required: Story = {
|
|
381
437
|
args: {
|
|
382
438
|
...Default.args,
|
|
@@ -393,7 +449,8 @@ export const Required: Story = {
|
|
|
393
449
|
return { args, value }
|
|
394
450
|
},
|
|
395
451
|
template: `
|
|
396
|
-
<div
|
|
452
|
+
<div>
|
|
453
|
+
<p class="mb-2 text-caption text-grey-darken-2">Ce champ est obligatoire</p>
|
|
397
454
|
<SyTextField v-bind="args" v-model="value" />
|
|
398
455
|
</div>
|
|
399
456
|
`,
|
|
@@ -413,6 +470,7 @@ Pour afficher l'astérisque sur un champ requis, il faut activer la prop \`displ
|
|
|
413
470
|
{
|
|
414
471
|
name: 'Template',
|
|
415
472
|
code: `<template>
|
|
473
|
+
<p class="mb-2 text-caption text-grey-darken-2">Ce champ est obligatoire</p>
|
|
416
474
|
<SyTextField
|
|
417
475
|
v-model="value"
|
|
418
476
|
required
|
|
@@ -451,7 +509,7 @@ export const RequiredWithAsterisk: Story = {
|
|
|
451
509
|
},
|
|
452
510
|
template: `
|
|
453
511
|
<div class="d-flex flex-wrap align-center">
|
|
454
|
-
|
|
512
|
+
<SyTextField v-bind="args" v-model="value" />
|
|
455
513
|
</div>
|
|
456
514
|
`,
|
|
457
515
|
}
|
|
@@ -837,6 +895,7 @@ Cette story montre l'utilisation des règles de validation standard. Le champ :
|
|
|
837
895
|
code: `<SyTextField
|
|
838
896
|
v-model="value"
|
|
839
897
|
label="Champ avec validation"
|
|
898
|
+
helpText="Le champ doit contenir à minima 3 caractères"
|
|
840
899
|
:customRules="[
|
|
841
900
|
{
|
|
842
901
|
type: 'minLength',
|
|
@@ -862,6 +921,7 @@ Cette story montre l'utilisation des règles de validation standard. Le champ :
|
|
|
862
921
|
v-model="value"
|
|
863
922
|
v-bind="args"
|
|
864
923
|
label="Champ avec validation"
|
|
924
|
+
helpText="Le champ doit contenir à minima 3 caractères"
|
|
865
925
|
:customRules="[
|
|
866
926
|
{
|
|
867
927
|
type: 'minLength',
|
|
@@ -960,12 +1020,13 @@ Cette story montre un cas d'usage courant : la validation d'une adresse email. L
|
|
|
960
1020
|
v-model="value"
|
|
961
1021
|
autocomplete="email"
|
|
962
1022
|
label="Email"
|
|
1023
|
+
helpText="Format attendu : nom@domaine.fr"
|
|
963
1024
|
required
|
|
964
1025
|
:customRules="[
|
|
965
1026
|
{
|
|
966
1027
|
type: 'email',
|
|
967
1028
|
options: {
|
|
968
|
-
message: 'L'email n'est pas valide'
|
|
1029
|
+
message: 'L'email n'est pas valide'
|
|
969
1030
|
successMessage: 'L'email est valide'
|
|
970
1031
|
}
|
|
971
1032
|
}
|
|
@@ -986,6 +1047,7 @@ Cette story montre un cas d'usage courant : la validation d'une adresse email. L
|
|
|
986
1047
|
v-model="value"
|
|
987
1048
|
v-bind="args"
|
|
988
1049
|
label="Email"
|
|
1050
|
+
helpText="Format attendu : nom@domaine.fr"
|
|
989
1051
|
autocomplete="email"
|
|
990
1052
|
required
|
|
991
1053
|
:customRules="[
|
|
@@ -1023,6 +1085,7 @@ Cette story montre l'utilisation de la règle \`matchPattern\` pour valider un f
|
|
|
1023
1085
|
code: `<SyTextField
|
|
1024
1086
|
v-model="value"
|
|
1025
1087
|
label="Code postal"
|
|
1088
|
+
helpText="Exemple : 31000"
|
|
1026
1089
|
autocomplete="postal-code"
|
|
1027
1090
|
required
|
|
1028
1091
|
:customRules="[
|
|
@@ -1051,6 +1114,7 @@ Cette story montre l'utilisation de la règle \`matchPattern\` pour valider un f
|
|
|
1051
1114
|
v-model="value"
|
|
1052
1115
|
v-bind="args"
|
|
1053
1116
|
label="Code postal"
|
|
1117
|
+
helpText="Exemple : 31000"
|
|
1054
1118
|
autocomplete="postal-code"
|
|
1055
1119
|
required
|
|
1056
1120
|
:customRules="[
|
|
@@ -1307,9 +1371,11 @@ export const FormValidation: Story = {
|
|
|
1307
1371
|
v-model="nomValue"
|
|
1308
1372
|
label="Nom"
|
|
1309
1373
|
placeholder="Votre nom"
|
|
1374
|
+
autocomplete="family-name"
|
|
1310
1375
|
required
|
|
1311
1376
|
show-success-messages
|
|
1312
1377
|
class="mb-4"
|
|
1378
|
+
aria-describedby="nom-rule"
|
|
1313
1379
|
/>
|
|
1314
1380
|
|
|
1315
1381
|
<SyTextField
|
|
@@ -1317,9 +1383,11 @@ export const FormValidation: Story = {
|
|
|
1317
1383
|
v-model="prenomValue"
|
|
1318
1384
|
label="Prénom"
|
|
1319
1385
|
placeholder="Votre prénom"
|
|
1386
|
+
autocomplete="given-name"
|
|
1320
1387
|
:custom-rules="prenomRules"
|
|
1321
1388
|
show-success-messages
|
|
1322
1389
|
class="mb-4"
|
|
1390
|
+
aria-describedby="prenom-rule"
|
|
1323
1391
|
/>
|
|
1324
1392
|
|
|
1325
1393
|
<SyTextField
|
|
@@ -1330,15 +1398,16 @@ export const FormValidation: Story = {
|
|
|
1330
1398
|
:custom-rules="ageRules"
|
|
1331
1399
|
show-success-messages
|
|
1332
1400
|
class="mb-4"
|
|
1401
|
+
aria-describedby="age-rule"
|
|
1333
1402
|
/>
|
|
1334
1403
|
</div>
|
|
1335
1404
|
|
|
1336
1405
|
<div class="text-caption mb-4">
|
|
1337
1406
|
<strong>Règles de validation :</strong>
|
|
1338
1407
|
<ul>
|
|
1339
|
-
<li>Nom : Champ requis</li>
|
|
1340
|
-
<li>Prénom : Minimum 3 caractères</li>
|
|
1341
|
-
<li>Âge : Uniquement des chiffres</li>
|
|
1408
|
+
<li id="nom-rule">Nom : Champ requis</li>
|
|
1409
|
+
<li id="prenom-rule">Prénom : Minimum 3 caractères</li>
|
|
1410
|
+
<li id="age-rule">Âge : Uniquement des chiffres</li>
|
|
1342
1411
|
</ul>
|
|
1343
1412
|
</div>
|
|
1344
1413
|
|
|
@@ -1542,6 +1611,7 @@ export const WithoutSuccessMessages: Story = {
|
|
|
1542
1611
|
<SyTextField
|
|
1543
1612
|
v-model="value1"
|
|
1544
1613
|
v-bind="args"
|
|
1614
|
+
autocomplete="email"
|
|
1545
1615
|
showSuccessMessages
|
|
1546
1616
|
/>
|
|
1547
1617
|
</div>
|
|
@@ -1551,6 +1621,7 @@ export const WithoutSuccessMessages: Story = {
|
|
|
1551
1621
|
<SyTextField
|
|
1552
1622
|
v-model="value2"
|
|
1553
1623
|
v-bind="args"
|
|
1624
|
+
autocomplete="email"
|
|
1554
1625
|
:showSuccessMessages="false"
|
|
1555
1626
|
/>
|
|
1556
1627
|
</div>
|
|
@@ -1583,6 +1654,7 @@ export const WithoutSuccessMessages: Story = {
|
|
|
1583
1654
|
<SyTextField
|
|
1584
1655
|
v-model="email"
|
|
1585
1656
|
label="Email"
|
|
1657
|
+
autocomplete="email"
|
|
1586
1658
|
:custom-rules="[{
|
|
1587
1659
|
type: 'matchPattern',
|
|
1588
1660
|
options: {
|
|
@@ -1597,6 +1669,7 @@ export const WithoutSuccessMessages: Story = {
|
|
|
1597
1669
|
<SyTextField
|
|
1598
1670
|
v-model="email"
|
|
1599
1671
|
label="Email"
|
|
1672
|
+
autocomplete="email"
|
|
1600
1673
|
:custom-rules="[{
|
|
1601
1674
|
type: 'matchPattern',
|
|
1602
1675
|
options: {
|