@cnamts/synapse 1.0.1 → 1.0.2
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/README.md +1 -1
- package/dist/{DateFilter-BmRuzQ9Z.js → DateFilter-YWOTbfeL.js} +1 -1
- package/dist/{NumberFilter-CnIPDHqx.js → NumberFilter-DMmMgALM.js} +1 -1
- package/dist/{PeriodFilter-CZwZ8CnQ.js → PeriodFilter-Bok5BHcn.js} +1 -1
- package/dist/SelectFilter-BKud2WhN.js +136 -0
- package/dist/{TextFilter-DTxZHJwX.js → TextFilter-DvMf2thH.js} +1 -1
- package/dist/components/Accordion/Accordion.d.ts +2 -1
- package/dist/components/Accordion/composables/useAccordionGroupCommunication.d.ts +5 -0
- package/dist/components/Accordion/composables/useAccordionKeyboardNavigation.d.ts +12 -0
- package/dist/components/Accordion/composables/useAccordionState.d.ts +13 -0
- package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +85 -0
- package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
- package/dist/components/Customs/SySelect/SySelect.d.ts +33 -13
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -2
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +1585 -1452
- package/dist/components/DatePicker/DatePicker/DatePicker.d.ts +16 -2
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +3 -1
- package/dist/components/DatePicker/composables/index.d.ts +2 -0
- package/dist/components/DatePicker/composables/useAsteriskDisplay.d.ts +14 -0
- package/dist/components/DatePicker/composables/useDateAutoClamp.d.ts +16 -0
- package/dist/components/DatePicker/composables/useDateRangeInput.d.ts +1 -1
- package/dist/components/DatePicker/composables/useDisplayedDateString.d.ts +3 -0
- package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +1 -0
- package/dist/components/DatePicker/composables/useMonthButtonCustomization.d.ts +5 -2
- package/dist/components/NirField/NirField.d.ts +7 -3
- package/dist/components/NirField/nirValidation.d.ts +1 -1
- package/dist/components/PasswordField/PasswordField.d.ts +2 -0
- package/dist/components/PeriodField/PeriodField.d.ts +52 -8
- package/dist/components/PhoneField/PhoneField.d.ts +2 -2
- package/dist/components/RangeField/RangeField.d.ts +2 -0
- package/dist/components/SearchListField/SearchListField.d.ts +9 -0
- package/dist/components/SyTextArea/SyTextArea.d.ts +2 -0
- package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +14 -9
- package/dist/components/Tables/SyTable/SyTable.d.ts +12 -7
- package/dist/components/Tables/common/SyTablePagination.d.ts +1636 -0
- package/dist/components/Tables/common/TableHeader.d.ts +2 -20
- package/dist/components/Tables/common/filters/SelectFilter.d.ts +5 -5
- package/dist/components/Tables/common/filters/getFilterComponent.d.ts +1 -0
- package/dist/components/Tables/common/filters/locales.d.ts +4 -0
- package/dist/components/Tables/common/filters/logics/date.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/number.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/period.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/select.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/text.d.ts +1 -0
- package/dist/components/Tables/common/locales.d.ts +21 -0
- package/dist/components/Tables/common/organizeColumns/OrganizeColumns.d.ts +267 -0
- package/dist/components/Tables/common/organizeColumns/sortHeaders.d.ts +2 -0
- package/dist/components/Tables/common/tableFilterUtils.d.ts +1 -0
- package/dist/components/Tables/common/tableStorageUtils.d.ts +41 -1
- package/dist/components/Tables/common/tableUtils.d.ts +42 -5
- package/dist/components/Tables/common/types.d.ts +19 -8
- package/dist/components/Tables/common/usePagination.d.ts +22 -0
- package/dist/components/Tables/common/useTableCheckbox.d.ts +20 -0
- package/dist/components/Tables/common/useTableHeaders.d.ts +76 -0
- package/dist/components/Tables/common/useTableItems.d.ts +24 -0
- package/dist/components/Tables/common/useTableOptions.d.ts +18 -0
- package/dist/components/ToolbarContainer/ToolbarContainer.d.ts +11 -0
- package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +9 -2
- package/dist/components/index.d.ts +8 -6
- package/dist/design-system-v3.js +58 -56
- package/dist/design-system-v3.umd.cjs +22 -22
- package/dist/main-Cx8qG7YR.js +16344 -0
- package/dist/stories/Accessibilite/Vuetify/VuetifyItems.d.ts +14 -2
- package/dist/stories/DesignTokens/StylesTypographiques.stories.new.d.ts +8 -0
- package/dist/stories/DesignTokens/TypographyDisplay.d.ts +28 -0
- package/dist/stories/DesignTokens/vue-shims.d.ts +6 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/common/imgs/accessibility-svgrepo-com.svg +4 -0
- package/src/components/Accordion/Accessibilite/AccessibilityGuide.mdx +249 -0
- package/src/components/Accordion/Accordion.vue +48 -76
- package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +146 -0
- package/src/components/Accordion/composables/__tests__/useAccordionKeyboardNavigation.spec.ts +209 -0
- package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +144 -0
- package/src/components/Accordion/composables/useAccordionGroupCommunication.ts +52 -0
- package/src/components/Accordion/composables/useAccordionKeyboardNavigation.ts +111 -0
- package/src/components/Accordion/composables/useAccordionState.ts +59 -0
- package/src/components/Accordion/tests/__snapshots__/accordion.spec.ts.snap +3 -0
- package/src/components/Customs/SyCheckbox/Accessibilite.mdx +303 -0
- package/src/components/Customs/SyCheckbox/SyCheckbox.mdx +50 -0
- package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +630 -0
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +326 -0
- package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +201 -0
- package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +1 -0
- package/src/components/Customs/SyInputSelect/SyInputSelect.vue +8 -1
- package/src/components/Customs/SySelect/SySelect.stories.ts +160 -0
- package/src/components/Customs/SySelect/SySelect.vue +291 -32
- package/src/components/Customs/SySelect/tests/SySelect.spec.ts +230 -0
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +3 -2
- package/src/components/Customs/SyTextField/SyTextField.vue +19 -8
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +241 -31
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +305 -57
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.events.spec.ts +161 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +4 -2
- package/src/components/DatePicker/DatePicker/DatePicker.stories.ts +259 -137
- package/src/components/DatePicker/DatePicker/DatePicker.vue +153 -25
- package/src/components/DatePicker/DatePicker/tests/DatePicker.events.spec.ts +189 -0
- package/src/components/DatePicker/DatePicker/{DatePicker.spec.ts → tests/DatePicker.spec.ts} +1 -15
- package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +24 -14
- package/src/components/DatePicker/DateTextInput/DateTextInput.events.spec.ts +148 -0
- package/src/components/DatePicker/DateTextInput/DateTextInput.spec.ts +3 -1
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +200 -5
- package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +241 -31
- package/src/components/DatePicker/composables/index.ts +2 -0
- package/src/components/DatePicker/composables/tests/useDateAutoClamp.spec.ts +190 -0
- package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +182 -4
- package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +105 -80
- package/src/components/DatePicker/composables/useAsteriskDisplay.ts +31 -0
- package/src/components/DatePicker/composables/useDateAutoClamp.ts +136 -0
- package/src/components/DatePicker/composables/useDateRangeInput.ts +21 -18
- package/src/components/DatePicker/composables/useDisplayedDateString.ts +13 -1
- package/src/components/DatePicker/composables/useInputBlurHandler.ts +84 -20
- package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +149 -51
- package/src/components/DiacriticPicker/DiacriticPicker.stories.ts +10 -0
- package/src/components/ErrorPage/Accessibilite.stories.ts +8 -0
- package/src/components/ErrorPage/ErrorPage.vue +12 -6
- package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +4 -4
- package/src/components/NirField/NirField.mdx +22 -9
- package/src/components/NirField/NirField.stories.ts +26 -2
- package/src/components/NirField/NirField.vue +209 -22
- package/src/components/NirField/nirValidation.ts +17 -3
- package/src/components/NirField/tests/NirField.spec.ts +2 -2
- package/src/components/NotFoundPage/Accessibilite.stories.ts +8 -0
- package/src/components/NotFoundPage/NotFoundPage.vue +2 -1
- package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +8 -6
- package/src/components/PaginatedTable/PaginatedTable.mdx +2 -0
- package/src/components/PasswordField/PasswordField.stories.ts +4 -0
- package/src/components/PasswordField/PasswordField.vue +3 -0
- package/src/components/PeriodField/PeriodField.vue +2 -0
- package/src/components/PhoneField/PhoneField.stories.ts +15 -15
- package/src/components/PhoneField/PhoneField.vue +1 -1
- package/src/components/RangeField/RangeField.stories.ts +9 -0
- package/src/components/RangeField/RangeField.vue +4 -0
- package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +12 -0
- package/src/components/SearchListField/SearchListField.vue +5 -0
- package/src/components/SyTextArea/SyTextArea.vue +3 -0
- package/src/components/SyTextArea/tests/SyTextArea.spec.ts +0 -1
- package/src/components/Tables/SyServerTable/FilterRules.stories.ts +632 -15
- package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -5
- package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +2844 -1377
- package/src/components/Tables/SyServerTable/SyServerTable.vue +155 -66
- package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +256 -4
- package/src/components/Tables/SyTable/FilterRules.stories.ts +183 -0
- package/src/components/Tables/SyTable/SyTable.mdx +14 -4
- package/src/components/Tables/SyTable/SyTable.stories.ts +1265 -477
- package/src/components/Tables/SyTable/SyTable.vue +152 -72
- package/src/components/Tables/SyTable/tests/SyTable.spec.ts +366 -4
- package/src/components/Tables/common/SyTableFilter.vue +3 -56
- package/src/components/Tables/common/SyTablePagination.vue +375 -0
- package/src/components/Tables/common/TableHeader.vue +10 -26
- package/src/components/Tables/common/filters/SelectFilter.vue +131 -22
- package/src/components/Tables/common/filters/getFilterComponent.ts +54 -0
- package/src/components/Tables/common/filters/locales.ts +4 -0
- package/src/components/Tables/common/filters/logics/date.ts +12 -0
- package/src/components/Tables/common/filters/logics/number.ts +48 -0
- package/src/components/Tables/common/filters/logics/period.ts +25 -0
- package/src/components/Tables/common/filters/logics/select.ts +27 -0
- package/src/components/Tables/common/filters/logics/tests/TextFilterLogic.spec.ts +177 -0
- package/src/components/Tables/common/filters/logics/text.ts +62 -0
- package/src/components/Tables/common/filters/tests/TextFilter.spec.ts +11 -11
- package/src/components/Tables/common/locales.ts +24 -0
- package/src/components/Tables/common/organizeColumns/OrganizeColumns.vue +269 -0
- package/src/components/Tables/common/organizeColumns/sortHeaders.ts +9 -0
- package/src/components/Tables/common/tableFilterUtils.ts +43 -295
- package/src/components/Tables/common/tableStorageUtils.ts +27 -2
- package/src/components/Tables/common/tableStyles.scss +26 -0
- package/src/components/Tables/common/tableUtils.ts +3 -16
- package/src/components/Tables/common/tests/SyTablePagination.spec.ts +170 -0
- package/src/components/Tables/common/tests/filterByRange.spec.ts +215 -0
- package/src/components/Tables/common/tests/tableFilterUtils.spec.ts +0 -14
- package/src/components/Tables/common/tests/tableUtils.spec.ts +7 -51
- package/src/components/Tables/common/types.ts +17 -6
- package/src/components/Tables/common/usePagination.ts +83 -0
- package/src/components/Tables/common/useTableCheckbox.ts +58 -0
- package/src/components/Tables/common/useTableHeaders.ts +88 -0
- package/src/components/Tables/common/useTableItems.ts +87 -0
- package/src/components/Tables/common/useTableOptions.ts +93 -0
- package/src/components/ToolbarContainer/ToolbarContainer.mdx +16 -0
- package/src/components/ToolbarContainer/ToolbarContainer.stories.ts +675 -0
- package/src/components/ToolbarContainer/ToolbarContainer.vue +128 -0
- package/src/components/ToolbarContainer/tests/ToolbarContainer.spec.ts +156 -0
- package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +74 -0
- package/src/components/UserMenuBtn/UserMenuBtn.vue +19 -17
- package/src/components/index.ts +8 -6
- package/src/stories/Accessibilite/Aculturation/AuditDesignSystem.mdx +293 -20
- package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +448 -54
- package/src/stories/Accessibilite/Audit/RGAA.mdx +231 -23
- package/src/stories/Accessibilite/Avancement/Avancement.mdx +591 -7
- package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +139 -38
- package/src/stories/Accessibilite/Introduction.mdx +258 -18
- package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +221 -31
- package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +204 -22
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +537 -24
- package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +577 -70
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru.mdx +382 -31
- package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +419 -81
- package/src/stories/Accessibilite/Vuetify/Vuetify.mdx +132 -6
- package/src/stories/Accessibilite/Vuetify/Vuetify.stories.ts +370 -146
- package/src/stories/Accessibilite/Vuetify/VuetifyItems.ts +35 -57
- package/src/stories/Demarrer/Accueil.stories.ts +20 -5
- package/src/stories/DesignTokens/StylesTypographiques.mdx +10 -9
- package/src/stories/DesignTokens/StylesTypographiques.stories.new.ts +397 -0
- package/src/stories/DesignTokens/StylesTypographiques.stories.ts +397 -0
- package/src/stories/DesignTokens/TypographyDisplay.vue +155 -0
- package/src/stories/DesignTokens/vue-shims.d.ts +6 -0
- package/src/stories/GuideDuDev/LesBreackingChanges.mdx +0 -2
- package/src/stories/GuideDuDev/MigrationDepuisBridge.mdx +1 -1
- package/src/stories/GuideDuDev/MigrationDepuisVue2.mdx +1 -1
- package/src/stories/GuideDuDev/PortailAgent.mdx +10 -0
- package/src/stories/GuideDuDev/PortailAgent.stories.ts +506 -0
- package/src/stories/GuideDuDev/Theme.mdx +41 -0
- package/dist/SelectFilter-Cj-GW2Cc.js +0 -97
- package/dist/main-WDqeoGM-.js +0 -14788
- package/src/components/PaginatedTable/tests/__snapshots__/PaginatedTable.spec.ts.snap +0 -886
- package/src/components/Tables/SyServerTable/tests/__snapshots__/SyServerTable.spec.ts.snap +0 -521
- package/src/components/Tables/SyTable/tests/__snapshots__/SyTable.spec.ts.snap +0 -521
- package/src/stories/DesignTokens/ThemePA.mdx +0 -35
package/package.json
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
2
|
+
<svg width="800px" height="800px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM9.25 3.75C9.25 4.44036 8.69036 5 8 5C7.30964 5 6.75 4.44036 6.75 3.75C6.75 3.05964 7.30964 2.5 8 2.5C8.69036 2.5 9.25 3.05964 9.25 3.75ZM12 8H9.41901L11.2047 13H9.081L8 9.97321L6.91901 13H4.79528L6.581 8H4V6H12V8Z" fill="#000000"/>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks';
|
|
2
|
+
import * as AccordionStories from '../Accordion.stories';
|
|
3
|
+
import AccessibilityIcon from '@/common/imgs/accessibility-svgrepo-com.svg';
|
|
4
|
+
|
|
5
|
+
<Meta of={AccordionStories} />
|
|
6
|
+
|
|
7
|
+
<div className="accessibility-guide">
|
|
8
|
+
<Title>Guide d'Accessibilité du Composant Accordion</Title>
|
|
9
|
+
|
|
10
|
+
<div className="intro-section">
|
|
11
|
+
<img
|
|
12
|
+
src={AccessibilityIcon}
|
|
13
|
+
alt="Icône d'accessibilité"
|
|
14
|
+
className="accessibility-icon"
|
|
15
|
+
/>
|
|
16
|
+
<p className="intro-text">
|
|
17
|
+
Le composant Accordion a été conçu en suivant rigoureusement les recommandations d'accessibilité du W3C,
|
|
18
|
+
notamment le modèle <a href="https://www.w3.org/WAI/ARIA/apg/patterns/accordion/examples/accordion/" target="_blank" rel="noopener noreferrer">WAI-ARIA Authoring Practices</a>.
|
|
19
|
+
Ce guide détaille comment notre implémentation respecte ces standards et garantit une expérience utilisateur inclusive.
|
|
20
|
+
</p>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div className="criteria-section">
|
|
24
|
+
<h2>Critères d'accessibilité respectés</h2>
|
|
25
|
+
|
|
26
|
+
<div className="criteria-card">
|
|
27
|
+
<div className="criteria-header">
|
|
28
|
+
<span className="criteria-icon">🔍</span>
|
|
29
|
+
<h3>Structure sémantique</h3>
|
|
30
|
+
</div>
|
|
31
|
+
<ul>
|
|
32
|
+
<li><strong>Rôles ARIA appropriés</strong> : <code>role="button"</code> pour les en-têtes et <code>role="region"</code> pour les panneaux de contenu</li>
|
|
33
|
+
<li><strong>Niveaux de titres personnalisables</strong> : Utilisation dynamique des balises <code>h1</code> à <code>h6</code> selon le contexte</li>
|
|
34
|
+
<li><strong>Relations entre éléments</strong> : Connexion entre en-têtes et panneaux via <code>aria-controls</code> et <code>aria-labelledby</code></li>
|
|
35
|
+
</ul>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div className="criteria-card">
|
|
39
|
+
<div className="criteria-header">
|
|
40
|
+
<span className="criteria-icon">⌨️</span>
|
|
41
|
+
<h3>Navigation clavier complète</h3>
|
|
42
|
+
</div>
|
|
43
|
+
<ul>
|
|
44
|
+
<li><strong>Touches Espace et Entrée</strong> : Pour activer/désactiver les panneaux</li>
|
|
45
|
+
<li><strong>Touches fléchées</strong> : Navigation entre les en-têtes (↑ et ↓)</li>
|
|
46
|
+
<li><strong>Touches Home/End</strong> : Accès rapide au premier/dernier en-tête</li>
|
|
47
|
+
<li><strong>Gestion intelligente</strong> : Contournement automatique des éléments désactivés</li>
|
|
48
|
+
</ul>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div className="criteria-card">
|
|
52
|
+
<div className="criteria-header">
|
|
53
|
+
<span className="criteria-icon">📱</span>
|
|
54
|
+
<h3>États et retours d'information</h3>
|
|
55
|
+
</div>
|
|
56
|
+
<ul>
|
|
57
|
+
<li><strong>État d'expansion</strong> : <code>aria-expanded</code> indique si un panneau est ouvert ou fermé</li>
|
|
58
|
+
<li><strong>État de désactivation</strong> : <code>aria-disabled</code> signale les éléments non disponibles</li>
|
|
59
|
+
<li><strong>Indication visuelle</strong> : Rotation de l'icône et changements de couleur pour indiquer l'état</li>
|
|
60
|
+
<li><strong>Focus visible</strong> : Indication claire de l'élément actuellement focalisé</li>
|
|
61
|
+
</ul>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div className="criteria-card">
|
|
65
|
+
<div className="criteria-header">
|
|
66
|
+
<span className="criteria-icon">🎨</span>
|
|
67
|
+
<h3>Personnalisation accessible</h3>
|
|
68
|
+
</div>
|
|
69
|
+
<ul>
|
|
70
|
+
<li><strong>Contraste configurable</strong> : Options de couleurs pour garantir un contraste suffisant</li>
|
|
71
|
+
<li><strong>Taille et espacement</strong> : Dimensions adaptées pour faciliter l'interaction</li>
|
|
72
|
+
<li><strong>Cohérence visuelle</strong> : Comportement prévisible dans différents contextes</li>
|
|
73
|
+
</ul>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div className="demo-section">
|
|
78
|
+
<h2>Démonstration interactive</h2>
|
|
79
|
+
<p>
|
|
80
|
+
Explorez ci-dessous un exemple d'Accordion entièrement accessible.
|
|
81
|
+
Essayez de naviguer en utilisant uniquement votre clavier pour tester l'accessibilité.
|
|
82
|
+
</p>
|
|
83
|
+
<Primary />
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div className="best-practices">
|
|
87
|
+
<h2>Bonnes pratiques d'utilisation</h2>
|
|
88
|
+
<ul>
|
|
89
|
+
<li>Utilisez des titres concis et descriptifs pour les en-têtes</li>
|
|
90
|
+
<li>Évitez de placer des éléments interactifs complexes à l'intérieur du contenu des panneaux</li>
|
|
91
|
+
<li>Maintenez une cohérence dans l'utilisation des niveaux de titres</li>
|
|
92
|
+
<li>Limitez le nombre d'accordéons sur une même page pour éviter la surcharge cognitive</li>
|
|
93
|
+
</ul>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div className="resources-section">
|
|
97
|
+
<h2>Ressources supplémentaires</h2>
|
|
98
|
+
<ul>
|
|
99
|
+
<li><a href="https://www.w3.org/WAI/ARIA/apg/patterns/accordion/" target="_blank" rel="noopener noreferrer">Guide des pratiques d'auteur WAI-ARIA pour les accordéons</a></li>
|
|
100
|
+
<li><a href="https://www.w3.org/WAI/WCAG21/quickref/" target="_blank" rel="noopener noreferrer">Référence rapide WCAG 2.1</a></li>
|
|
101
|
+
<li><a href="https://inclusive-components.design/collapsible-sections/" target="_blank" rel="noopener noreferrer">Inclusive Components: Collapsible Sections</a></li>
|
|
102
|
+
</ul>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<style>
|
|
107
|
+
{`
|
|
108
|
+
.accessibility-guide {
|
|
109
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
110
|
+
max-width: 1200px;
|
|
111
|
+
margin: 0 auto;
|
|
112
|
+
padding: 2rem;
|
|
113
|
+
color: #333;
|
|
114
|
+
line-height: 1.6;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.intro-section {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: 2rem;
|
|
121
|
+
margin: 2rem 0;
|
|
122
|
+
padding: 1.5rem;
|
|
123
|
+
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
|
|
124
|
+
border-radius: 12px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.accessibility-icon {
|
|
128
|
+
width: 80px;
|
|
129
|
+
height: 80px;
|
|
130
|
+
object-fit: contain;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.intro-text {
|
|
134
|
+
font-size: 1.1rem;
|
|
135
|
+
margin: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.criteria-section {
|
|
139
|
+
margin: 3rem 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.criteria-section h2 {
|
|
143
|
+
font-size: 1.8rem;
|
|
144
|
+
margin-bottom: 1.5rem;
|
|
145
|
+
color: #2c3e50;
|
|
146
|
+
border-bottom: 2px solid #e0e0e0;
|
|
147
|
+
padding-bottom: 0.5rem;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.criteria-card {
|
|
151
|
+
background-color: #ffffff;
|
|
152
|
+
border-radius: 8px;
|
|
153
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05), 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
154
|
+
padding: 1.5rem;
|
|
155
|
+
margin-bottom: 1.5rem;
|
|
156
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.criteria-card:hover {
|
|
160
|
+
transform: translateY(-2px);
|
|
161
|
+
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.08), 0 3px 6px rgba(0, 0, 0, 0.12);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.criteria-header {
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
margin-bottom: 1rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.criteria-icon {
|
|
171
|
+
font-size: 1.8rem;
|
|
172
|
+
margin-right: 1rem;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.criteria-header h3 {
|
|
176
|
+
margin: 0;
|
|
177
|
+
font-size: 1.4rem;
|
|
178
|
+
color: #1976d2;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.criteria-card ul {
|
|
182
|
+
margin: 0;
|
|
183
|
+
padding-left: 1.5rem;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.criteria-card li {
|
|
187
|
+
margin-bottom: 0.5rem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.criteria-card strong {
|
|
191
|
+
color: #455a64;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.criteria-card code {
|
|
195
|
+
background-color: #f5f5f5;
|
|
196
|
+
padding: 0.2rem 0.4rem;
|
|
197
|
+
border-radius: 4px;
|
|
198
|
+
font-size: 0.9rem;
|
|
199
|
+
color: #e91e63;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.demo-section {
|
|
203
|
+
margin: 3rem 0;
|
|
204
|
+
padding: 2rem;
|
|
205
|
+
background-color: #f9f9f9;
|
|
206
|
+
border-radius: 8px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.best-practices {
|
|
210
|
+
margin: 3rem 0;
|
|
211
|
+
padding: 1.5rem;
|
|
212
|
+
background-color: #e8f5e9;
|
|
213
|
+
border-left: 4px solid #4caf50;
|
|
214
|
+
border-radius: 4px;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.best-practices h2 {
|
|
218
|
+
color: #2e7d32;
|
|
219
|
+
margin-top: 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.resources-section {
|
|
223
|
+
margin: 3rem 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.resources-section a {
|
|
227
|
+
color: #1976d2;
|
|
228
|
+
text-decoration: none;
|
|
229
|
+
border-bottom: 1px dotted;
|
|
230
|
+
transition: color 0.2s ease;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.resources-section a:hover {
|
|
234
|
+
color: #0d47a1;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@media (max-width: 768px) {
|
|
238
|
+
.intro-section {
|
|
239
|
+
flex-direction: column;
|
|
240
|
+
text-align: center;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.accessibility-icon {
|
|
244
|
+
margin-bottom: 1rem;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
`}
|
|
248
|
+
</style>
|
|
249
|
+
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
|
3
2
|
import useCustomizableOptions, { type CustomizableOptions } from '@/composables/useCustomizableOptions'
|
|
4
3
|
import { config } from '@/components/Accordion/config'
|
|
5
4
|
import { mdiChevronRight } from '@mdi/js'
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
// Importation des composables
|
|
7
|
+
import useAccordionState from './composables/useAccordionState'
|
|
8
|
+
import useAccordionGroupCommunication from './composables/useAccordionGroupCommunication'
|
|
9
|
+
import useAccordionKeyboardNavigation, { type AccordionItem as KeyboardNavigationItem } from './composables/useAccordionKeyboardNavigation'
|
|
8
10
|
|
|
9
11
|
interface ContentObject {
|
|
10
12
|
title: string
|
|
@@ -16,6 +18,7 @@
|
|
|
16
18
|
title: string
|
|
17
19
|
content: string | ContentObject
|
|
18
20
|
headingLevel?: number
|
|
21
|
+
disabled?: boolean
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
interface Props extends CustomizableOptions {
|
|
@@ -41,83 +44,38 @@
|
|
|
41
44
|
|
|
42
45
|
const options = useCustomizableOptions(config, props)
|
|
43
46
|
|
|
47
|
+
// Génération d'un ID unique pour cette instance d'accordéon
|
|
44
48
|
const instanceId = `accordion-${Math.random().toString(36).substring(2, 9)}`
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
sourceInstanceId: instanceId,
|
|
66
|
-
groupId: props.groupId,
|
|
67
|
-
itemId,
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
window.dispatchEvent(event)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const toggleItem = (itemId: string) => {
|
|
74
|
-
// Si cet élément est déjà focalisé, on le garde en mémoire
|
|
75
|
-
const wasFocused = focusedItemId.value === itemId
|
|
76
|
-
|
|
77
|
-
const index = openItems.value.indexOf(itemId)
|
|
78
|
-
if (index === -1) {
|
|
79
|
-
openItems.value.push(itemId)
|
|
50
|
+
// Utilisation du composable pour gérer l'état de l'accordéon
|
|
51
|
+
const {
|
|
52
|
+
toggleItem,
|
|
53
|
+
isItemOpen,
|
|
54
|
+
isItemFocused,
|
|
55
|
+
setFocus,
|
|
56
|
+
} = useAccordionState()
|
|
57
|
+
|
|
58
|
+
// Utilisation du composable pour gérer la communication entre accordéons
|
|
59
|
+
const { emitFocusChange } = useAccordionGroupCommunication(
|
|
60
|
+
instanceId,
|
|
61
|
+
props.groupId,
|
|
62
|
+
itemId => setFocus(itemId),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
// Utilisation du composable pour gérer la navigation clavier
|
|
66
|
+
const { handleKeyNavigation } = useAccordionKeyboardNavigation(
|
|
67
|
+
props.items as KeyboardNavigationItem[],
|
|
68
|
+
(itemId) => {
|
|
80
69
|
setFocus(itemId)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (!wasFocused) {
|
|
85
|
-
setFocus(itemId)
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
setFocus(null)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const isItemOpen = (itemId: string) => {
|
|
94
|
-
return openItems.value.includes(itemId)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const isItemFocused = (itemId: string) => {
|
|
98
|
-
return focusedItemId.value === itemId
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Méthode pour définir explicitement le focus sur un élément
|
|
102
|
-
const setFocus = (itemId: string | null) => {
|
|
103
|
-
if (focusedItemId.value === itemId) return
|
|
104
|
-
|
|
105
|
-
focusedItemId.value = itemId
|
|
106
|
-
emitFocusChange(itemId)
|
|
107
|
-
}
|
|
70
|
+
emitFocusChange(itemId)
|
|
71
|
+
},
|
|
72
|
+
)
|
|
108
73
|
|
|
74
|
+
// Fonction pour déterminer le niveau de titre à utiliser
|
|
109
75
|
const getHeadingTag = (item: AccordionItem) => {
|
|
110
76
|
const level = item.headingLevel || props.headingLevel
|
|
111
77
|
return `h${level}`
|
|
112
78
|
}
|
|
113
|
-
|
|
114
|
-
onMounted(() => {
|
|
115
|
-
window.addEventListener(ACCORDION_FOCUS_EVENT, handleFocusChange as unknown as EventListener)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
onBeforeUnmount(() => {
|
|
119
|
-
window.removeEventListener(ACCORDION_FOCUS_EVENT, handleFocusChange as unknown as EventListener)
|
|
120
|
-
})
|
|
121
79
|
</script>
|
|
122
80
|
|
|
123
81
|
<template>
|
|
@@ -130,7 +88,7 @@
|
|
|
130
88
|
}"
|
|
131
89
|
>
|
|
132
90
|
<div
|
|
133
|
-
v-for="item in items"
|
|
91
|
+
v-for="(item, index) in items"
|
|
134
92
|
:key="item.id"
|
|
135
93
|
class="sy-accordion-item"
|
|
136
94
|
:class="`bg-${options.accordion.backgroundColor}`"
|
|
@@ -140,12 +98,20 @@
|
|
|
140
98
|
role="button"
|
|
141
99
|
:aria-expanded="isItemOpen(item.id)"
|
|
142
100
|
:aria-controls="`accordion-content-${item.id}`"
|
|
101
|
+
:aria-disabled="item.disabled ? 'true' : 'false'"
|
|
143
102
|
class="sy-accordion-button"
|
|
144
|
-
:class="{
|
|
103
|
+
:class="{
|
|
104
|
+
'sy-accordion-button--focused': isItemFocused(item.id),
|
|
105
|
+
'sy-accordion-button--disabled': item.disabled
|
|
106
|
+
}"
|
|
145
107
|
tabindex="0"
|
|
146
|
-
@click="toggleItem(item.id)"
|
|
147
|
-
@keydown.space.prevent="toggleItem(item.id)"
|
|
148
|
-
@keydown.enter.prevent="toggleItem(item.id)"
|
|
108
|
+
@click="!item.disabled && toggleItem(item.id)"
|
|
109
|
+
@keydown.space.prevent="!item.disabled && toggleItem(item.id)"
|
|
110
|
+
@keydown.enter.prevent="!item.disabled && toggleItem(item.id)"
|
|
111
|
+
@keydown.down.prevent="!item.disabled && handleKeyNavigation($event, item.id, index)"
|
|
112
|
+
@keydown.up.prevent="!item.disabled && handleKeyNavigation($event, item.id, index)"
|
|
113
|
+
@keydown.home.prevent="!item.disabled && handleKeyNavigation($event, item.id, index)"
|
|
114
|
+
@keydown.end.prevent="!item.disabled && handleKeyNavigation($event, item.id, index)"
|
|
149
115
|
>
|
|
150
116
|
<component
|
|
151
117
|
:is="getHeadingTag(item)"
|
|
@@ -316,4 +282,10 @@
|
|
|
316
282
|
.sy-accordion-icon--open {
|
|
317
283
|
transform: rotate(90deg);
|
|
318
284
|
}
|
|
285
|
+
|
|
286
|
+
/* Style pour les éléments désactivés */
|
|
287
|
+
.sy-accordion-button--disabled {
|
|
288
|
+
opacity: 0.6;
|
|
289
|
+
cursor: not-allowed;
|
|
290
|
+
}
|
|
319
291
|
</style>
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import useAccordionGroupCommunication from '../useAccordionGroupCommunication'
|
|
3
|
+
|
|
4
|
+
describe('useAccordionGroupCommunication', () => {
|
|
5
|
+
const instanceId = 'test-instance'
|
|
6
|
+
const groupId = 'test-group'
|
|
7
|
+
const mockOnFocusChange = vi.fn()
|
|
8
|
+
|
|
9
|
+
// Espionner les méthodes addEventListener et removeEventListener de window
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.spyOn(window, 'addEventListener')
|
|
12
|
+
vi.spyOn(window, 'removeEventListener')
|
|
13
|
+
vi.spyOn(window, 'dispatchEvent')
|
|
14
|
+
|
|
15
|
+
// Réinitialiser les mocks avant chaque test
|
|
16
|
+
mockOnFocusChange.mockReset()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
vi.restoreAllMocks()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('initialization', () => {
|
|
24
|
+
it('adds event listener on mount', () => {
|
|
25
|
+
// Utiliser le composable pour tester son initialisation
|
|
26
|
+
useAccordionGroupCommunication(
|
|
27
|
+
instanceId,
|
|
28
|
+
groupId,
|
|
29
|
+
mockOnFocusChange,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
// Vérifier que le composable a bien ajouté l'écouteur d'événements
|
|
33
|
+
// Note: Nous ne pouvons pas vérifier directement l'appel à addEventListener car
|
|
34
|
+
// il est appelé dans le hook onMounted qui n'est pas exécuté dans le contexte de test
|
|
35
|
+
// Nous vérifions donc simplement que le test s'exécute sans erreur
|
|
36
|
+
expect(true).toBe(true)
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('emitFocusChange', () => {
|
|
41
|
+
it('dispatches a custom event with the correct details', () => {
|
|
42
|
+
const { emitFocusChange } = useAccordionGroupCommunication(
|
|
43
|
+
instanceId,
|
|
44
|
+
groupId,
|
|
45
|
+
mockOnFocusChange,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const itemId = 'test-item'
|
|
49
|
+
emitFocusChange(itemId)
|
|
50
|
+
|
|
51
|
+
expect(window.dispatchEvent).toHaveBeenCalledWith(
|
|
52
|
+
expect.objectContaining({
|
|
53
|
+
type: 'accordion-focus-changed',
|
|
54
|
+
detail: {
|
|
55
|
+
sourceInstanceId: instanceId,
|
|
56
|
+
groupId,
|
|
57
|
+
itemId,
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('dispatches a custom event with null itemId', () => {
|
|
64
|
+
const { emitFocusChange } = useAccordionGroupCommunication(
|
|
65
|
+
instanceId,
|
|
66
|
+
groupId,
|
|
67
|
+
mockOnFocusChange,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
emitFocusChange(null)
|
|
71
|
+
|
|
72
|
+
expect(window.dispatchEvent).toHaveBeenCalledWith(
|
|
73
|
+
expect.objectContaining({
|
|
74
|
+
type: 'accordion-focus-changed',
|
|
75
|
+
detail: {
|
|
76
|
+
sourceInstanceId: instanceId,
|
|
77
|
+
groupId,
|
|
78
|
+
itemId: null,
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
describe('handleFocusChange', () => {
|
|
86
|
+
it('ignores events from the same instance', () => {
|
|
87
|
+
const { handleFocusChange } = useAccordionGroupCommunication(
|
|
88
|
+
instanceId,
|
|
89
|
+
groupId,
|
|
90
|
+
mockOnFocusChange,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
const event = new CustomEvent('accordion-focus-changed', {
|
|
94
|
+
detail: {
|
|
95
|
+
sourceInstanceId: instanceId, // Même instance
|
|
96
|
+
groupId,
|
|
97
|
+
itemId: 'test-item',
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
handleFocusChange(event)
|
|
102
|
+
|
|
103
|
+
expect(mockOnFocusChange).not.toHaveBeenCalled()
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('ignores events from different groups', () => {
|
|
107
|
+
const { handleFocusChange } = useAccordionGroupCommunication(
|
|
108
|
+
instanceId,
|
|
109
|
+
groupId,
|
|
110
|
+
mockOnFocusChange,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
const event = new CustomEvent('accordion-focus-changed', {
|
|
114
|
+
detail: {
|
|
115
|
+
sourceInstanceId: 'other-instance',
|
|
116
|
+
groupId: 'other-group', // Groupe différent
|
|
117
|
+
itemId: 'test-item',
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
handleFocusChange(event)
|
|
122
|
+
|
|
123
|
+
expect(mockOnFocusChange).not.toHaveBeenCalled()
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('calls onFocusChange with null when receiving a valid event', () => {
|
|
127
|
+
const { handleFocusChange } = useAccordionGroupCommunication(
|
|
128
|
+
instanceId,
|
|
129
|
+
groupId,
|
|
130
|
+
mockOnFocusChange,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
const event = new CustomEvent('accordion-focus-changed', {
|
|
134
|
+
detail: {
|
|
135
|
+
sourceInstanceId: 'other-instance', // Instance différente
|
|
136
|
+
groupId, // Même groupe
|
|
137
|
+
itemId: 'test-item',
|
|
138
|
+
},
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
handleFocusChange(event)
|
|
142
|
+
|
|
143
|
+
expect(mockOnFocusChange).toHaveBeenCalledWith(null)
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
})
|