@cnamts/synapse 1.0.23 → 1.0.24
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/AutocompleteFilter-BWLR3U7W.js +114 -0
- package/dist/AutocompleteFilter-D9jzRzAL.cjs +1 -0
- package/dist/{DateFilter-Dc-gSGwk.js → DateFilter-BpwFexzi.js} +1 -1
- package/dist/DateFilter-DTUl8hb1.cjs +1 -0
- package/dist/{NumberFilter-vP38Wp6j.js → NumberFilter-Bz_NTdX9.js} +3 -3
- package/dist/NumberFilter-MAEojdk0.cjs +1 -0
- package/dist/PeriodFilter-CC4WgIhl.cjs +1 -0
- package/dist/{PeriodFilter-Ba1uYUnT.js → PeriodFilter-DX_wy9g-.js} +1 -1
- package/dist/SelectFilter-BR3fvl-a.cjs +1 -0
- package/dist/SelectFilter-xqiPtPgX.js +135 -0
- package/dist/{TextFilter-B84dpnoq.js → TextFilter-BBl3JFqK.js} +7 -7
- package/dist/TextFilter-CCfYFl5F.cjs +1 -0
- package/dist/apLightTheme-CFSRrjv2.cjs +1 -0
- package/dist/apLightTheme-D1P4jcD0.js +1231 -0
- package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +7022 -9616
- package/dist/components/Amelipro/AmeliproCarousel/AmeliproCarousel.d.ts +2 -2
- package/dist/components/Amelipro/AmeliproIconBtn/AmeliproIconBtn.d.ts +2 -2
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/AmeliproPostalAddressCityRow.d.ts +40 -40
- package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +60 -60
- package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +7168 -9762
- package/dist/components/Amelipro/AmeliproStepper/AmeliproStepper.d.ts +2 -2
- package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +7501 -10095
- package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +21 -21
- package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +41 -41
- package/dist/components/Amelipro/StructureMenu/StructureTabs/StructureTabs.d.ts +2 -2
- package/dist/components/CookiesSelection/CookiesInformation/CookiesInformation.d.ts +20 -498
- package/dist/components/Customs/Selects/SyAutocomplete/SyAutocomplete.d.ts +108 -146
- package/dist/components/Customs/Selects/SyInputSelect/SyInputSelect.d.ts +5 -5
- package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +12 -16
- package/dist/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.d.ts +8 -8
- package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +28 -506
- package/dist/components/Customs/SyRadioGroup/SyRadioGroup.d.ts +28 -506
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +65 -85
- package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +627 -771
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +315 -402
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +112 -155
- package/dist/components/DatePicker/composables/index.d.ts +1 -0
- package/dist/components/DatePicker/composables/useDatePickerFocusTrap.d.ts +11 -0
- package/dist/components/DatePicker/composables/useDateTextField.d.ts +4 -4
- package/dist/components/DatePicker/composables/useDateValidation.d.ts +3 -3
- package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +2 -2
- package/dist/components/DatePicker/composables/useManualDateValidation.d.ts +2 -2
- package/dist/components/HeaderNavigationBar/HeaderNavigationBar.d.ts +4 -4
- package/dist/components/HeaderToolbar/HeaderToolbar.d.ts +20 -28
- package/dist/components/LunarCalendar/useLunarCalendarValidation.d.ts +3 -3
- package/dist/components/MonthPicker/MonthPicker.d.ts +86 -122
- package/dist/components/MonthPicker/MonthPickerText/MonthPickerInput.d.ts +85 -121
- package/dist/components/NirField/NirField.d.ts +206 -270
- package/dist/components/NirField/locales.d.ts +10 -10
- package/dist/components/NirField/useNirValidation.d.ts +64 -0
- package/dist/components/PasswordField/PasswordField.d.ts +8 -9
- package/dist/components/PeriodField/PeriodField.d.ts +1352 -1640
- package/dist/components/PhoneField/PhoneField.d.ts +88 -124
- package/dist/components/RangeField/RangeSlider/RangeSlider.d.ts +12 -12
- package/dist/components/SyTextArea/SyTextArea.d.ts +34 -14
- package/dist/components/SyTextArea/useDefaultValidationRules.d.ts +11 -0
- package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +9 -6
- package/dist/components/Tables/SyTable/SyTable.d.ts +9 -6
- package/dist/components/Tables/common/SyTableFilter.d.ts +2 -3
- package/dist/components/Tables/common/SyTablePagination.d.ts +17 -19
- package/dist/components/Tables/common/filters/AutocompleteFilter.d.ts +120 -0
- package/dist/components/Tables/common/filters/locales.d.ts +0 -1
- package/dist/components/Tables/common/types.d.ts +19 -3
- package/dist/components/Tables/common/useClickableTableRow.d.ts +17 -0
- package/dist/components/Tables/common/usePagination.d.ts +3 -1
- package/dist/components/Tables/common/usePinnedColumns.d.ts +31 -0
- package/dist/components/Tables/common/useTableHeaders.d.ts +2 -0
- package/dist/components/Tables/common/useTableRowCheckboxAccessibility.d.ts +5 -0
- package/dist/components/UploadWorkflow/UploadWorkflow.d.ts +6 -6
- package/dist/composables/date/useDatePickerAccessibility.d.ts +1 -1
- package/dist/composables/rules/useFieldValidation.d.ts +4 -4
- package/dist/composables/unifyValidation/useCustomValidation.d.ts +8 -0
- package/dist/composables/unifyValidation/useValidation.d.ts +102 -0
- package/dist/composables/unifyValidation/useVuetifyValidation.d.ts +18 -0
- package/dist/composables/useFormFieldErrorHandling.d.ts +2 -2
- package/dist/composables/validation/useFormValidation.d.ts +11 -2
- package/dist/composables/validation/useValidation.d.ts +15 -9
- package/dist/design-system-v3.d.ts +2 -0
- package/dist/design-system-v3.js +186 -187
- package/dist/design-system-v3.umd.cjs +1 -1066
- package/dist/{main-aLKwdMi1.js → main-BtTqyn4z.js} +16434 -15672
- package/dist/main-C1e3eoxd.cjs +1067 -0
- package/dist/main.d.ts +0 -1
- package/dist/synapse.css +1 -0
- package/dist/tooth-11-D3sLWv2n.cjs +1 -0
- package/dist/tooth-12-CXrLuH03.cjs +1 -0
- package/dist/tooth-13-BSfo5fpT.cjs +1 -0
- package/dist/tooth-14-DMzulx0h.cjs +1 -0
- package/dist/tooth-15-BKRFVi-9.cjs +1 -0
- package/dist/tooth-16-CpuxAbuM.cjs +1 -0
- package/dist/tooth-17-BPoahUdg.cjs +1 -0
- package/dist/tooth-18-DhHJz8sy.cjs +1 -0
- package/dist/tooth-21-Dgd5hn_X.cjs +1 -0
- package/dist/tooth-22-C2Tn19sB.cjs +1 -0
- package/dist/tooth-23-C9uaaSGb.cjs +1 -0
- package/dist/tooth-24-BrK9UGpf.cjs +1 -0
- package/dist/tooth-25-CE_EfGNp.cjs +1 -0
- package/dist/tooth-26-Ctv4i9Fy.cjs +1 -0
- package/dist/tooth-27-C5J7JkWM.cjs +1 -0
- package/dist/tooth-28-Z9oWqjo0.cjs +1 -0
- package/dist/tooth-31-BrYqmkTi.cjs +1 -0
- package/dist/tooth-32-BNNR0oCZ.cjs +1 -0
- package/dist/tooth-33-DuxvqO2J.cjs +1 -0
- package/dist/tooth-34-BCSCXMB6.cjs +1 -0
- package/dist/tooth-35-BLUXkX88.cjs +1 -0
- package/dist/tooth-36-IrKHYqlA.cjs +1 -0
- package/dist/tooth-37-BYqpdMwo.cjs +1 -0
- package/dist/tooth-38-B_eNXXdu.cjs +1 -0
- package/dist/tooth-41-Ddva4Ot8.cjs +1 -0
- package/dist/tooth-42-szcDqlM0.cjs +1 -0
- package/dist/tooth-43-B3ka6rQm.cjs +1 -0
- package/dist/tooth-44-CazyQucj.cjs +1 -0
- package/dist/tooth-45-B4HQtc8n.cjs +1 -0
- package/dist/tooth-46-BPM40gbG.cjs +1 -0
- package/dist/tooth-47-Dvr20dlh.cjs +1 -0
- package/dist/tooth-48-Bd8ljGsF.cjs +1 -0
- package/dist/tooth-51-OBpwCOF3.cjs +1 -0
- package/dist/tooth-52-aKxyHcmq.cjs +1 -0
- package/dist/tooth-53-vCwJjTOc.cjs +1 -0
- package/dist/tooth-54-DsWu2iFy.cjs +1 -0
- package/dist/tooth-55-BxC1X2Dn.cjs +1 -0
- package/dist/tooth-61-BbLvxMQi.cjs +1 -0
- package/dist/tooth-62-CmTkWczP.cjs +1 -0
- package/dist/tooth-63-DI7l_2qI.cjs +1 -0
- package/dist/tooth-64-B21sOsJh.cjs +1 -0
- package/dist/tooth-65-D2ZC2VEr.cjs +1 -0
- package/dist/tooth-71-D473PPO5.cjs +1 -0
- package/dist/tooth-72-Drh1wnNu.cjs +1 -0
- package/dist/tooth-73-DzlwYI23.cjs +1 -0
- package/dist/tooth-74-8aGvcZPg.cjs +1 -0
- package/dist/tooth-75-BFK7At_r.cjs +1 -0
- package/dist/tooth-81-BZmR-I0M.cjs +1 -0
- package/dist/tooth-82-euVfUUZV.cjs +1 -0
- package/dist/tooth-83-KV010j64.cjs +1 -0
- package/dist/tooth-84-BBg1RjhZ.cjs +1 -0
- package/dist/tooth-85-Cr-kc1wM.cjs +1 -0
- package/dist/vuetifyConfig.js +561 -0
- package/dist/vuetifyConfig.umd.cjs +1 -0
- package/package.json +10 -4
- package/src/assets/overrides/_btns.scss +0 -6
- package/src/assets/overrides/_icons.scss +9 -1
- package/src/assets/overrides/_typography.scss +0 -10
- package/src/components/Amelipro/AmeliproAutoCompleteField/__tests__/__snapshots__/AmeliproAutoCompleteField.spec.ts.snap +2 -2
- package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/__tests__/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +1 -1
- package/src/components/Amelipro/AmeliproTextArea/__tests__/__snapshots__/AmeliproTextArea.spec.ts.snap +2 -2
- package/src/components/Captcha/accessibilite/Accessibility.mdx +86 -8
- package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +12 -12
- package/src/components/ChipList/ChipList.stories.ts +0 -15
- package/src/components/ChipList/ChipList.vue +5 -1
- package/src/components/ChipList/accessibilite/Accessibility.mdx +83 -10
- package/src/components/ChipList/tests/ChipList.a11y.spec.ts +41 -0
- package/src/components/Customs/Selects/SelectBtnField/accessibilite/Accessibility.mdx +0 -9
- package/src/components/Customs/Selects/SyAutocomplete/SyAutocomplete.vue +22 -5
- package/src/components/Customs/Selects/SyAutocomplete/tests/SyAutocomplete.spec.ts +143 -0
- package/src/components/Customs/Selects/SyAutocomplete/utils/ariaManager.ts +14 -10
- package/src/components/Customs/Selects/SyInputSelect/SyInputSelect.stories.ts +4 -4
- package/src/components/Customs/Selects/SyInputSelect/SyInputSelect.vue +8 -9
- package/src/components/Customs/Selects/SyInputSelect/tests/SyInputSelect.spec.ts +10 -10
- package/src/components/Customs/Selects/SySelect/SySelect.vue +14 -11
- package/src/components/Customs/Selects/SySelect/tests/SySelect.spec.ts +54 -0
- package/src/components/Customs/SyCheckBoxGroup/SyCheckBoxGroup.vue +6 -9
- package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +10 -16
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +16 -11
- package/src/components/Customs/SyCheckbox/accessibilite/Accessibility.mdx +35 -0
- package/src/components/Customs/SyCheckbox/tests/SyCheckbox.a11y.spec.ts +134 -2
- package/src/components/Customs/SyForm/SyForm.stories.ts +31 -5
- package/src/components/Customs/SyRadioGroup/SyRadioGroup.vue +4 -7
- package/src/components/Customs/SyTextField/SyTextField.mdx +1 -1
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +29 -27
- package/src/components/Customs/SyTextField/SyTextField.vue +154 -157
- package/src/components/Customs/SyTextField/tests/SyTextField.a11y.spec.ts +32 -0
- package/src/components/Customs/SyTextField/tests/SyTextField.spec.ts +120 -11
- package/src/components/DatePicker/CalendarMode/DatePicker.stories.ts +62 -58
- package/src/components/DatePicker/CalendarMode/DatePicker.vue +330 -223
- package/src/components/DatePicker/CalendarMode/accessibilite/Accessibility.mdx +82 -0
- package/src/components/DatePicker/CalendarMode/tests/DatePicker.a11y.spec.ts +141 -0
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +2 -56
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +195 -159
- package/src/components/DatePicker/ComplexDatePicker/accessibilite/Accessibility.mdx +76 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +10 -10
- package/src/components/DatePicker/DatePickerValidationExample/CalendarMode.stories.ts +8 -8
- package/src/components/DatePicker/DatePickerValidationExample/ComplexDatePicker.stories.ts +106 -8
- package/src/components/DatePicker/DatePickerValidationExample/DateTextInput.stories.ts +12 -11
- package/src/components/DatePicker/DatePickerValidationExample/MultiMode.stories.ts +12 -12
- package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +0 -12
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +63 -57
- package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +3 -0
- package/src/components/DatePicker/DateTextInput/accessibilite/Accessibility.mdx +66 -0
- package/src/components/DatePicker/DateTextInput/tests/DateTextInput.spec.ts +52 -1
- package/src/components/DatePicker/composables/index.ts +1 -0
- package/src/components/DatePicker/composables/tests/useCalendarKeyboardNavigation.spec.ts +109 -65
- package/src/components/DatePicker/composables/tests/useDatePickerFocusTrap.spec.ts +138 -0
- package/src/components/DatePicker/composables/tests/useDateValidation.spec.ts +74 -18
- package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +39 -0
- package/src/components/DatePicker/composables/tests/useManualDateValidation.spec.ts +91 -0
- package/src/components/DatePicker/composables/useCalendarKeyboardNavigation.ts +442 -36
- package/src/components/DatePicker/composables/useDatePickerFocusTrap.ts +92 -0
- package/src/components/DatePicker/composables/useDateTextField.ts +7 -6
- package/src/components/DatePicker/composables/useDateValidation.ts +36 -35
- package/src/components/DatePicker/composables/useInputBlurHandler.ts +3 -3
- package/src/components/DatePicker/composables/useManualDateValidation.ts +6 -2
- package/src/components/DiacriticPicker/accessibilite/Accessibility.mdx +76 -8
- package/src/components/HeaderBar/HeaderBar.stories.ts +14 -2
- package/src/components/Logo/accessibilite/Accessibility.mdx +73 -11
- package/src/components/LogoBrandSection/accessibilite/Accessibility.mdx +85 -9
- package/src/components/LunarCalendar/tests/LunarCalendar.spec.ts +3 -1
- package/src/components/LunarCalendar/useLunarCalendarValidation.ts +4 -5
- package/src/components/MonthPicker/tests/MonthPicker.spec.ts +2 -1
- package/src/components/MonthPicker/tests/__snapshots__/MonthPicker.spec.ts.snap +7 -7
- package/src/components/NirField/NirField.stories.ts +4 -0
- package/src/components/NirField/NirField.vue +64 -260
- package/src/components/NirField/accessibilite/Accessibility.mdx +2 -2
- package/src/components/NirField/locales.ts +1 -1
- package/src/components/NirField/tests/NirField.spec.ts +6 -0
- package/src/components/NirField/useNirValidation.ts +271 -0
- package/src/components/PasswordField/PasswordField.stories.ts +4 -4
- package/src/components/PasswordField/PasswordField.vue +18 -24
- package/src/components/PasswordField/tests/PasswordField.spec.ts +6 -3
- package/src/components/PeriodField/PeriodField.stories.ts +4 -4
- package/src/components/PeriodField/PeriodField.vue +57 -57
- package/src/components/PeriodField/__tests__/PeriodField.async.spec.ts +32 -0
- package/src/components/PeriodField/accessibilite/Accessibility.mdx +68 -8
- package/src/components/PeriodField/tests/PeriodField.spec.ts +28 -2
- package/src/components/PhoneField/PhoneField.vue +5 -6
- package/src/components/PhoneField/tests/PhoneField.spec.ts +1 -0
- package/src/components/RangeField/RangeField.vue +6 -0
- package/src/components/SyTextArea/SyTextArea.stories.ts +138 -2
- package/src/components/SyTextArea/SyTextArea.vue +53 -23
- package/src/components/SyTextArea/tests/SyTextArea.spec.ts +126 -3
- package/src/components/SyTextArea/useDefaultValidationRules.ts +74 -0
- package/src/components/Tables/SyServerTable/SyServerTable.mdx +25 -0
- package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +673 -1
- package/src/components/Tables/SyServerTable/SyServerTable.vue +148 -91
- package/src/components/Tables/SyServerTable/tests/SyServerTable.a11y.spec.ts +58 -0
- package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +122 -0
- package/src/components/Tables/SyTable/SyTable.mdx +25 -0
- package/src/components/Tables/SyTable/SyTable.stories.ts +452 -1
- package/src/components/Tables/SyTable/SyTable.vue +130 -56
- package/src/components/Tables/SyTable/tests/SyTable.a11y.spec.ts +57 -0
- package/src/components/Tables/SyTable/tests/SyTable.spec.ts +108 -0
- package/src/components/Tables/common/SyTableFilter.vue +22 -2
- package/src/components/Tables/common/TableHeader.vue +5 -1
- package/src/components/Tables/common/filters/AutocompleteFilter.vue +160 -0
- package/src/components/Tables/common/filters/NumberFilter.vue +1 -1
- package/src/components/Tables/common/filters/SelectFilter.vue +10 -11
- package/src/components/Tables/common/filters/TextFilter.vue +1 -1
- package/src/components/Tables/common/filters/getFilterComponent.ts +8 -1
- package/src/components/Tables/common/filters/locales.ts +0 -1
- package/src/components/Tables/common/filters/tests/AutocompleteFilter.a11y.spec.ts +110 -0
- package/src/components/Tables/common/filters/tests/AutocompleteFilter.spec.ts +203 -0
- package/src/components/Tables/common/filters/tests/SelectFilter.a11y.spec.ts +104 -0
- package/src/components/Tables/common/filters/tests/SelectFilter.spec.ts +152 -16
- package/src/components/Tables/common/tableFilterUtils.ts +3 -0
- package/src/components/Tables/common/tableStyles.scss +48 -4
- package/src/components/Tables/common/tests/filterByRange.spec.ts +2 -1
- package/src/components/Tables/common/types.ts +13 -4
- package/src/components/Tables/common/useClickableTableRow.ts +103 -0
- package/src/components/Tables/common/usePagination.ts +13 -0
- package/src/components/Tables/common/usePinnedColumns.ts +237 -0
- package/src/components/Tables/common/useTableHeaders.ts +3 -3
- package/src/components/Tables/common/useTableRowCheckboxAccessibility.ts +41 -0
- package/src/composables/date/tests/useDatePickerAccessibility.spec.ts +2 -6
- package/src/composables/date/useDatePickerAccessibility.ts +42 -207
- package/src/composables/rules/tests/useFieldValidation.spec.ts +120 -120
- package/src/composables/rules/useFieldValidation.ts +34 -17
- package/src/composables/unifyValidation/tests/useCustomValidation.spec.ts +601 -0
- package/src/composables/unifyValidation/tests/useValidation.spec.ts +2048 -0
- package/src/composables/unifyValidation/tests/useVuetifyValidation.spec.ts +184 -0
- package/src/composables/unifyValidation/useCustomValidation.ts +95 -0
- package/src/composables/unifyValidation/useValidation.ts +190 -0
- package/src/composables/unifyValidation/useVuetifyValidation.ts +54 -0
- package/src/composables/useFormFieldErrorHandling.ts +4 -7
- package/src/composables/validation/tests/useFormValidation.spec.ts +14 -0
- package/src/composables/validation/tests/useValidation.spec.ts +116 -21
- package/src/composables/validation/useFormValidation.ts +20 -13
- package/src/composables/validation/useValidatable.ts +8 -1
- package/src/composables/validation/useValidation.ts +135 -99
- package/src/composantsVuetify/Introduction.mdx +48 -0
- package/src/composantsVuetify/VBtn/VBtn.mdx +72 -0
- package/src/composantsVuetify/VBtn/v-btn.stories.ts +121 -0
- package/src/composantsVuetify/VTooltip/VTooltip.mdx +32 -0
- package/src/composantsVuetify/VTooltip/v-tooltip.stories.ts +95 -0
- package/src/designTokens/tokens/cnam/cnamSemantic.ts +2 -2
- package/src/main.ts +0 -2
- package/src/stories/Components/Components.stories.ts +74 -9
- package/src/stories/Demarrer/Accueil.stories.ts +3 -3
- package/src/stories/GuideDuDev/Amelipro.mdx +15 -0
- package/src/stories/GuideDuDev/Amelipro.stories.ts +209 -0
- package/src/stories/GuideDuDev/vuetifyOptions.mdx +3 -3
- package/dist/SelectFilter-BioGT6Nn.js +0 -136
- package/dist/style.css +0 -1
- package/src/components/DatePicker/Accessibilite.mdx +0 -14
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { computed, nextTick, onMounted, onUnmounted, ref, type Ref } from 'vue'
|
|
2
|
+
import type { DataTableHeaders, TableColumnHeader } from './types'
|
|
3
|
+
|
|
4
|
+
// Fonction de throttling simple pour optimiser les performances
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
const useThrottleFn = <T extends (...args: any[]) => void>(fn: T, delay: number): T => {
|
|
7
|
+
let lastCall = 0
|
|
8
|
+
return ((...args: Parameters<T>) => {
|
|
9
|
+
const now = Date.now()
|
|
10
|
+
if (now - lastCall >= delay) {
|
|
11
|
+
lastCall = now
|
|
12
|
+
return fn(...args)
|
|
13
|
+
}
|
|
14
|
+
}) as T
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface UsePinnedColumnsOptions {
|
|
18
|
+
displayHeaders: Ref<DataTableHeaders[] | undefined>
|
|
19
|
+
reactiveColumnWidths: Ref<Record<string, number | string>>
|
|
20
|
+
pinnedColumns: Ref<Array<string | { key: string, side?: 'left' | 'right' }> | undefined>
|
|
21
|
+
pinnedColumnKey: Ref<string | undefined>
|
|
22
|
+
stickySelect: Ref<boolean>
|
|
23
|
+
showSelect: Ref<boolean>
|
|
24
|
+
showSelectSingle: Ref<boolean>
|
|
25
|
+
tableRef: Ref<{ $el?: Element } | undefined>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function usePinnedColumns({
|
|
29
|
+
displayHeaders,
|
|
30
|
+
reactiveColumnWidths,
|
|
31
|
+
pinnedColumns,
|
|
32
|
+
pinnedColumnKey,
|
|
33
|
+
stickySelect,
|
|
34
|
+
showSelect,
|
|
35
|
+
showSelectSingle,
|
|
36
|
+
tableRef,
|
|
37
|
+
}: UsePinnedColumnsOptions) {
|
|
38
|
+
const tableWrapperEl = ref<HTMLElement | null>(null)
|
|
39
|
+
const showPinnedLeftShadow = ref(false)
|
|
40
|
+
const showPinnedRightShadow = ref(false)
|
|
41
|
+
|
|
42
|
+
// Stocker la référence de la fonction pour éviter les fuites mémoire
|
|
43
|
+
const updatePinnedShadowsRef = ref<(() => void) | null>(null)
|
|
44
|
+
|
|
45
|
+
const parseWidthPx = (val: unknown): number => {
|
|
46
|
+
if (typeof val === 'number' && Number.isFinite(val)) return val
|
|
47
|
+
if (typeof val === 'string') {
|
|
48
|
+
const trimmed = val.trim()
|
|
49
|
+
if (trimmed.endsWith('px')) {
|
|
50
|
+
const n = Number.parseFloat(trimmed.slice(0, -2))
|
|
51
|
+
return Number.isFinite(n) ? n : 0
|
|
52
|
+
}
|
|
53
|
+
const n = Number.parseFloat(trimmed)
|
|
54
|
+
return Number.isFinite(n) ? n : 0
|
|
55
|
+
}
|
|
56
|
+
return 0
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const normalizedPinnedColumns = computed(() => {
|
|
60
|
+
const raw = pinnedColumns.value ?? (pinnedColumnKey.value ? [pinnedColumnKey.value] : [])
|
|
61
|
+
return raw.map((c) => {
|
|
62
|
+
if (typeof c === 'string') return { key: c, side: 'left' as const }
|
|
63
|
+
return { key: c.key, side: c.side ?? 'left' as const }
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const pinnedLeftKeys = computed(() =>
|
|
68
|
+
normalizedPinnedColumns.value.filter(c => c.side !== 'right').map(c => c.key),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
const pinnedRightKeys = computed(() =>
|
|
72
|
+
normalizedPinnedColumns.value.filter(c => c.side === 'right').map(c => c.key),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
const stickySelectActive = computed(() => Boolean(stickySelect.value) && (showSelect.value || showSelectSingle.value))
|
|
76
|
+
const hasPinnedSelectLeft = computed(() => pinnedLeftKeys.value.includes('data-table-select') || stickySelectActive.value)
|
|
77
|
+
|
|
78
|
+
const getColumnWidthPx = (headersList: TableColumnHeader[], key: string): number => {
|
|
79
|
+
if (key === 'data-table-select' || key === 'data-table-expand' || key === 'data-table-group') return 48
|
|
80
|
+
const storedWidth = reactiveColumnWidths.value[key]
|
|
81
|
+
if (storedWidth != null) return parseWidthPx(storedWidth)
|
|
82
|
+
const h = headersList.find(x => (x.key ?? x.value) === key)
|
|
83
|
+
return parseWidthPx(h?.width ?? h?.minWidth ?? h?.maxWidth)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const pinnedMeta = computed(() => {
|
|
87
|
+
const headersList = displayHeaders.value
|
|
88
|
+
if (!headersList) return { left: {} as Record<string, number>, right: {} as Record<string, number>, totalLeft: 0, totalRight: 0 }
|
|
89
|
+
|
|
90
|
+
const left: Record<string, number> = {}
|
|
91
|
+
let accLeft = 0
|
|
92
|
+
if (hasPinnedSelectLeft.value) {
|
|
93
|
+
left['data-table-select'] = 0
|
|
94
|
+
accLeft = getColumnWidthPx(headersList as TableColumnHeader[], 'data-table-select')
|
|
95
|
+
}
|
|
96
|
+
for (const h of headersList) {
|
|
97
|
+
const key = (h.key ?? h.value) as string | undefined
|
|
98
|
+
if (!key) continue
|
|
99
|
+
if (pinnedLeftKeys.value.includes(key)) {
|
|
100
|
+
left[key] = accLeft
|
|
101
|
+
accLeft += getColumnWidthPx(headersList as TableColumnHeader[], key)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const right: Record<string, number> = {}
|
|
106
|
+
let accRight = 0
|
|
107
|
+
for (const h of [...headersList].reverse()) {
|
|
108
|
+
const key = (h.key ?? h.value) as string | undefined
|
|
109
|
+
if (!key) continue
|
|
110
|
+
if (pinnedRightKeys.value.includes(key)) {
|
|
111
|
+
right[key] = accRight
|
|
112
|
+
accRight += getColumnWidthPx(headersList as TableColumnHeader[], key)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { left, right, totalLeft: accLeft, totalRight: accRight }
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const updatePinnedShadows = () => {
|
|
120
|
+
const el = tableWrapperEl.value
|
|
121
|
+
if (!el) return
|
|
122
|
+
const max = el.scrollWidth - el.clientWidth
|
|
123
|
+
showPinnedLeftShadow.value = pinnedMeta.value.totalLeft > 0 && el.scrollLeft > 0
|
|
124
|
+
showPinnedRightShadow.value = pinnedMeta.value.totalRight > 0 && max > 0 && el.scrollLeft < max - 1
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Fonction pour trouver le wrapper du tableau avec retry
|
|
128
|
+
const findTableWrapper = (): HTMLElement | null => {
|
|
129
|
+
const el = tableRef.value?.$el as HTMLElement | undefined
|
|
130
|
+
return el?.querySelector('.v-table__wrapper') as HTMLElement | null
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Initialiser la référence de la fonction
|
|
134
|
+
updatePinnedShadowsRef.value = updatePinnedShadows
|
|
135
|
+
|
|
136
|
+
// Appliquer le throttling pour optimiser les performances (60fps)
|
|
137
|
+
const updatePinnedShadowsThrottled = useThrottleFn(updatePinnedShadows, 16)
|
|
138
|
+
|
|
139
|
+
const pinnedEdgeVars = computed<Record<string, string>>(() => {
|
|
140
|
+
const { totalLeft, totalRight } = pinnedMeta.value
|
|
141
|
+
return {
|
|
142
|
+
...(totalLeft > 0 ? { '--sy-pinned-left-edge': `${totalLeft}px` } : {}),
|
|
143
|
+
...(totalRight > 0 ? { '--sy-pinned-right-edge': `${totalRight}px` } : {}),
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
// Only cellProps are needed here — headerProps are applied inline in the #headers slot template
|
|
148
|
+
const displayHeadersWithPinned = computed(() => {
|
|
149
|
+
const headersList = displayHeaders.value
|
|
150
|
+
if (!headersList) return headersList
|
|
151
|
+
|
|
152
|
+
const leftOffsets = pinnedMeta.value.left
|
|
153
|
+
const rightOffsets = pinnedMeta.value.right
|
|
154
|
+
|
|
155
|
+
if (Object.keys(leftOffsets).length === 0 && Object.keys(rightOffsets).length === 0) return headersList
|
|
156
|
+
|
|
157
|
+
return headersList.map((h) => {
|
|
158
|
+
const key = (h.key ?? h.value) as string | undefined
|
|
159
|
+
if (!key) return h
|
|
160
|
+
|
|
161
|
+
const left = leftOffsets[key]
|
|
162
|
+
const right = rightOffsets[key]
|
|
163
|
+
if (left === undefined && right === undefined) return h
|
|
164
|
+
|
|
165
|
+
const cellProps = (h.cellProps ?? {}) as Record<string, unknown>
|
|
166
|
+
const cellStyle = (cellProps.style ?? {}) as Record<string, string | number>
|
|
167
|
+
|
|
168
|
+
const stickyCellStyle: Record<string, string | number> = {
|
|
169
|
+
position: 'sticky',
|
|
170
|
+
zIndex: 'var(--sy-table-z-pinned-cell)',
|
|
171
|
+
background: 'rgb(var(--v-theme-surface))',
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const sideClass = left !== undefined ? 'sy-table__pinned--left' : 'sy-table__pinned--right'
|
|
175
|
+
if (left !== undefined) {
|
|
176
|
+
stickyCellStyle.left = `${left}px`
|
|
177
|
+
}
|
|
178
|
+
else if (right !== undefined) {
|
|
179
|
+
stickyCellStyle.right = `${right}px`
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
...h,
|
|
184
|
+
cellProps: {
|
|
185
|
+
...cellProps,
|
|
186
|
+
class: ['sy-table__pinned', sideClass, 'v-data-table-column--fixed', cellProps.class].filter(Boolean),
|
|
187
|
+
style: { ...cellStyle, ...stickyCellStyle },
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
onMounted(() => {
|
|
194
|
+
nextTick(() => {
|
|
195
|
+
let attempts = 0
|
|
196
|
+
const maxAttempts = 5
|
|
197
|
+
|
|
198
|
+
const tryFindWrapper = () => {
|
|
199
|
+
tableWrapperEl.value = findTableWrapper()
|
|
200
|
+
if (tableWrapperEl.value || attempts >= maxAttempts) {
|
|
201
|
+
if (tableWrapperEl.value && updatePinnedShadowsRef.value) {
|
|
202
|
+
updatePinnedShadowsRef.value()
|
|
203
|
+
tableWrapperEl.value.addEventListener('scroll', updatePinnedShadowsThrottled, { passive: true })
|
|
204
|
+
}
|
|
205
|
+
if (updatePinnedShadowsRef.value) {
|
|
206
|
+
window.addEventListener('resize', updatePinnedShadowsThrottled)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
attempts++
|
|
211
|
+
setTimeout(tryFindWrapper, 50)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
tryFindWrapper()
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
onUnmounted(() => {
|
|
220
|
+
if (tableWrapperEl.value && updatePinnedShadowsRef.value) {
|
|
221
|
+
tableWrapperEl.value.removeEventListener('scroll', updatePinnedShadowsThrottled)
|
|
222
|
+
}
|
|
223
|
+
if (updatePinnedShadowsRef.value) {
|
|
224
|
+
window.removeEventListener('resize', updatePinnedShadowsThrottled)
|
|
225
|
+
}
|
|
226
|
+
updatePinnedShadowsRef.value = null
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
showPinnedLeftShadow,
|
|
231
|
+
showPinnedRightShadow,
|
|
232
|
+
hasPinnedSelectLeft,
|
|
233
|
+
pinnedMeta,
|
|
234
|
+
pinnedEdgeVars,
|
|
235
|
+
displayHeadersWithPinned,
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -124,13 +124,13 @@ export function useTableHeaders({
|
|
|
124
124
|
*/
|
|
125
125
|
function getHeaderForColumn(column: TableColumnHeader): TableColumnHeader | undefined {
|
|
126
126
|
if (!normalizedHeaders.value) return undefined
|
|
127
|
-
const key = column.key
|
|
127
|
+
const key = column.key ?? undefined
|
|
128
128
|
if (key) {
|
|
129
129
|
const byKey = normalizedHeaders.value.find(h => h.key === key)
|
|
130
130
|
if (byKey) return byKey
|
|
131
131
|
}
|
|
132
|
-
// Fallback: try matching by value when key is not present or didn
|
|
133
|
-
const val = column.value
|
|
132
|
+
// Fallback: try matching by value when key is not present or didn't match
|
|
133
|
+
const val = typeof column.value === 'string' ? column.value : undefined
|
|
134
134
|
if (val) {
|
|
135
135
|
const byValue = normalizedHeaders.value.find(h => h.value === val)
|
|
136
136
|
if (byValue) return byValue
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
|
|
2
|
+
import { locales } from './locales'
|
|
3
|
+
|
|
4
|
+
export function useTableRowCheckboxAccessibility({
|
|
5
|
+
uniqueTableId,
|
|
6
|
+
}: {
|
|
7
|
+
uniqueTableId: string
|
|
8
|
+
}) {
|
|
9
|
+
const timeouts = ref<ReturnType<typeof setTimeout>[]>([])
|
|
10
|
+
|
|
11
|
+
const accessibilityRowCheckboxes = () => {
|
|
12
|
+
nextTick(() => {
|
|
13
|
+
const timeoutId = setTimeout(() => {
|
|
14
|
+
if (typeof document === 'undefined') return
|
|
15
|
+
|
|
16
|
+
const tableElement = document.getElementById(uniqueTableId)
|
|
17
|
+
if (!tableElement) return
|
|
18
|
+
|
|
19
|
+
const rowCheckboxes = tableElement.querySelectorAll('td .v-selection-control input[type="checkbox"]')
|
|
20
|
+
rowCheckboxes.forEach((checkbox, index) => {
|
|
21
|
+
const rowLabel = `${locales.selectRow} ${index + 1}`
|
|
22
|
+
checkbox.setAttribute('aria-label', rowLabel)
|
|
23
|
+
checkbox.setAttribute('title', rowLabel)
|
|
24
|
+
})
|
|
25
|
+
}, 100)
|
|
26
|
+
|
|
27
|
+
timeouts.value.push(timeoutId)
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
onMounted(() => {
|
|
32
|
+
accessibilityRowCheckboxes()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
onUnmounted(() => {
|
|
36
|
+
timeouts.value.forEach(clearTimeout)
|
|
37
|
+
timeouts.value = []
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
return { accessibilityRowCheckboxes }
|
|
41
|
+
}
|
|
@@ -120,14 +120,10 @@ describe('useDatePickerAccessibility', () => {
|
|
|
120
120
|
expect(buttons[2]?.getAttribute('aria-label')).toBe(null) // Pas de chevron-righ
|
|
121
121
|
})
|
|
122
122
|
|
|
123
|
-
it('
|
|
124
|
-
// Appeler updateAccessibility
|
|
123
|
+
it('ne crée pas de bloc sr-only instructions (comportement actuel)', async () => {
|
|
125
124
|
await updateAccessibility()
|
|
126
|
-
|
|
127
|
-
// Vérifier que les instructions pour les lecteurs d'écran ont été ajoutées
|
|
128
125
|
const srOnlyEl = document.querySelector('.sr-only-instructions')
|
|
129
|
-
expect(srOnlyEl).
|
|
130
|
-
expect(srOnlyEl?.textContent).toBe('Utilisez tab pour naviguer entre les dates et Entrée ou Espace pour sélectionner une date')
|
|
126
|
+
expect(srOnlyEl).toBeNull()
|
|
131
127
|
})
|
|
132
128
|
|
|
133
129
|
describe('handleKeyDown', () => {
|
|
@@ -8,46 +8,6 @@ import { nextTick, onBeforeUnmount, onMounted } from 'vue'
|
|
|
8
8
|
* @returns Des fonctions pour mettre à jour l'accessibilité du CalendarMode et gérer les événements clavier
|
|
9
9
|
*/
|
|
10
10
|
export function useDatePickerAccessibility() {
|
|
11
|
-
// Référence pour suivre si l'événement a déjà été traité
|
|
12
|
-
let isProcessingEnterKey = false
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Gestionnaire d'événements clavier pour simuler le comportement de la touche espace avec la touche entrée
|
|
16
|
-
* @param event L'événement clavier
|
|
17
|
-
*/
|
|
18
|
-
const handleKeyDown = (event: Event): void => {
|
|
19
|
-
const keyboardEvent = event as KeyboardEvent
|
|
20
|
-
// Si la touche entrée est pressée et que nous ne sommes pas déjà en train de traiter un événement
|
|
21
|
-
if (keyboardEvent.key === 'Enter' && !isProcessingEnterKey) {
|
|
22
|
-
// Marquer que nous sommes en train de traiter l'événement pour éviter les doublons
|
|
23
|
-
isProcessingEnterKey = true
|
|
24
|
-
|
|
25
|
-
// Empêcher le comportement par défaut de la touche entrée
|
|
26
|
-
keyboardEvent.preventDefault()
|
|
27
|
-
|
|
28
|
-
// Récupérer l'élément actuellement focalisé
|
|
29
|
-
const focusedElement = document.activeElement
|
|
30
|
-
|
|
31
|
-
// Simuler un événement de touche espace
|
|
32
|
-
if (focusedElement && focusedElement instanceof HTMLElement) {
|
|
33
|
-
// Créer et déclencher un événement de clic qui simule le comportement de l'espace
|
|
34
|
-
const clickEvent = new MouseEvent('click', {
|
|
35
|
-
bubbles: true,
|
|
36
|
-
cancelable: true,
|
|
37
|
-
view: window,
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
// Déclencher un seul événement de clic
|
|
41
|
-
focusedElement.dispatchEvent(clickEvent)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Réinitialiser l'état après un délai pour permettre le traitement des autres événements
|
|
45
|
-
setTimeout(() => {
|
|
46
|
-
isProcessingEnterKey = false
|
|
47
|
-
}, 100)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
11
|
/**
|
|
52
12
|
* Met à jour les attributs d'accessibilité du CalendarMode
|
|
53
13
|
* Ajoute des attributs ARIA et des instructions pour les lecteurs d'écran
|
|
@@ -60,189 +20,67 @@ export function useDatePickerAccessibility() {
|
|
|
60
20
|
const datePickerEl = document.querySelector('.v-date-picker')
|
|
61
21
|
if (!datePickerEl) return
|
|
62
22
|
|
|
63
|
-
// Ajouter
|
|
64
|
-
datePickerEl.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// Attribuer des labels significatifs basés sur la position ou l'icône
|
|
71
|
-
navigationButtons.forEach(async (button) => {
|
|
72
|
-
// find btn with aria-label contain item
|
|
73
|
-
if (button.className.includes('v-date-picker-controls__mode-btn')) {
|
|
74
|
-
button.removeAttribute('aria-label')
|
|
23
|
+
// Ajouter des labels de navigation sur les boutons comportant les icônes attendues
|
|
24
|
+
const navButtons = datePickerEl.querySelectorAll<HTMLButtonElement>('.v-date-picker-header button')
|
|
25
|
+
navButtons.forEach((button) => {
|
|
26
|
+
const icon = button.querySelector('i')
|
|
27
|
+
if (icon?.classList.contains('mdi-chevron-left')) {
|
|
28
|
+
button.setAttribute('aria-label', 'Mois précédent')
|
|
29
|
+
return
|
|
75
30
|
}
|
|
76
|
-
// Vérifier si le bouton contient un SVG ou une icône
|
|
77
|
-
const svgEl = button.querySelector('svg')
|
|
78
|
-
const iconEl = button.querySelector('.v-icon')
|
|
79
31
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// Traiter les boutons avec SVG
|
|
84
|
-
if (svgEl) {
|
|
85
|
-
const svgContent = svgEl.innerHTML
|
|
86
|
-
|
|
87
|
-
// Left arrow (previous month)
|
|
88
|
-
if (svgContent.includes('M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z')) {
|
|
89
|
-
const accessibleName = buttonText ? `${buttonText} (Mois précédent)` : 'Mois précédent'
|
|
90
|
-
button.setAttribute('aria-label', accessibleName)
|
|
91
|
-
}
|
|
92
|
-
// Right arrow (next month)
|
|
93
|
-
else if (svgContent.includes('M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z')) {
|
|
94
|
-
const accessibleName = buttonText ? `${buttonText} (Mois suivant)` : 'Mois suivant'
|
|
95
|
-
button.setAttribute('aria-label', accessibleName)
|
|
96
|
-
}
|
|
97
|
-
// Calendar icon
|
|
98
|
-
else if (svgContent.includes('M19,19H5V8H19M16,1V3H8V1H6V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3H18V1M17,12H12V17H17V12Z')) {
|
|
99
|
-
const accessibleName = buttonText ? `${buttonText} (Ouvrir le calendrier)` : 'Ouvrir le calendrier'
|
|
100
|
-
button.setAttribute('aria-label', accessibleName)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
// Traiter les boutons avec icônes Material Design
|
|
104
|
-
else if (iconEl) {
|
|
105
|
-
// Left arrow (previous month)
|
|
106
|
-
if (iconEl.classList.contains('mdi-chevron-left')) {
|
|
107
|
-
const accessibleName = buttonText ? `${buttonText} (Mois précédent)` : 'Mois précédent'
|
|
108
|
-
button.setAttribute('aria-label', accessibleName)
|
|
109
|
-
}
|
|
110
|
-
// Right arrow (next month)
|
|
111
|
-
else if (iconEl.classList.contains('mdi-chevron-right')) {
|
|
112
|
-
const accessibleName = buttonText ? `${buttonText} (Mois suivant)` : 'Mois suivant'
|
|
113
|
-
button.setAttribute('aria-label', accessibleName)
|
|
114
|
-
}
|
|
32
|
+
if (icon?.classList.contains('mdi-chevron-right')) {
|
|
33
|
+
button.setAttribute('aria-label', 'Mois suivant')
|
|
34
|
+
return
|
|
115
35
|
}
|
|
36
|
+
|
|
37
|
+
button.removeAttribute('aria-label')
|
|
116
38
|
})
|
|
117
39
|
|
|
118
|
-
// Ajouter
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
srOnlyHtmlEl.style.height = '1px'
|
|
129
|
-
srOnlyHtmlEl.style.padding = '0'
|
|
130
|
-
srOnlyHtmlEl.style.margin = '-1px'
|
|
131
|
-
srOnlyHtmlEl.style.overflow = 'hidden'
|
|
132
|
-
srOnlyHtmlEl.style.clip = 'rect(0, 0, 0, 0)'
|
|
133
|
-
srOnlyHtmlEl.style.whiteSpace = 'nowrap'
|
|
134
|
-
srOnlyHtmlEl.style.border = '0'
|
|
135
|
-
srOnlyEl.textContent = 'Utilisez tab pour naviguer entre les dates et Entrée ou Espace pour sélectionner une date'
|
|
136
|
-
datePickerEl.prepend(srOnlyEl)
|
|
137
|
-
}
|
|
40
|
+
// Ajouter les instructions pour lecteurs d'écran si elles n'existent pas déjà
|
|
41
|
+
// if (!datePickerEl.querySelector('.sr-only-instructions')) {
|
|
42
|
+
// const srOnly = document.createElement('div')
|
|
43
|
+
// srOnly.className = 'sr-only sr-only-instructions'
|
|
44
|
+
// srOnly.textContent = 'Utilisez tab pour naviguer entre les dates et Entrée ou Espace pour sélectionner une date'
|
|
45
|
+
// datePickerEl.prepend(srOnly)
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
// Ajouter un attribut role="application" au conteneur principal
|
|
49
|
+
// Ne pas forcer role="application" ni aria-label générique : on laisse les rôles natifs du picker (grille/boutons) et les labels existants.
|
|
138
50
|
|
|
139
|
-
//
|
|
140
|
-
// Utiliser des casts explicites pour rassurer TypeScript sur les types
|
|
141
|
-
datePickerEl.removeEventListener('keydown', handleKeyDown as EventListener) // Supprimer d'abord pour éviter les doublons
|
|
142
|
-
datePickerEl.addEventListener('keydown', handleKeyDown as EventListener)
|
|
51
|
+
// Ne pas surcharger Enter/Espace : laisser les comportements natifs des boutons
|
|
143
52
|
}
|
|
144
53
|
|
|
145
|
-
// Référence pour le MutationObserver
|
|
146
|
-
|
|
54
|
+
// Référence pour le MutationObserver (désactivé)
|
|
55
|
+
// const observer: MutationObserver | null = null
|
|
147
56
|
|
|
148
57
|
/**
|
|
149
58
|
* Corrige les attributs ARIA invalides dans le composant
|
|
150
|
-
*
|
|
59
|
+
* Ici on ne supprime plus globalement aria-expanded/aria-haspopup pour éviter de casser la combobox.
|
|
151
60
|
*/
|
|
152
61
|
const fixAriaAttributes = () => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
// Cibler les éléments dans les conteneurs CalendarMode et DateTextInput
|
|
156
|
-
const containers = document.querySelectorAll('.date-picker-container, .v-date-picker')
|
|
157
|
-
|
|
158
|
-
if (containers.length === 0) {
|
|
159
|
-
return
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const allInputsWithAriaExpanded = document.querySelectorAll('input[aria-expanded]')
|
|
163
|
-
allInputsWithAriaExpanded.forEach((input) => {
|
|
164
|
-
if (input) {
|
|
165
|
-
input.removeAttribute('aria-expanded')
|
|
166
|
-
}
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
// Pour chaque conteneur, rechercher et corriger les attributs ARIA invalides
|
|
170
|
-
containers.forEach((container) => {
|
|
171
|
-
if (!container) return
|
|
62
|
+
// Désormais no-op pour éviter de retirer des attributs utiles.
|
|
63
|
+
}
|
|
172
64
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
element.removeAttribute('aria-haspopup')
|
|
180
|
-
// Intentionally keep aria-controls intact so valid popup relationships remain
|
|
181
|
-
})
|
|
65
|
+
/**
|
|
66
|
+
* Simule un clic sur l'élément focalisé lorsque la touche Entrée est pressée.
|
|
67
|
+
* Ne touche pas aux autres touches (espace, etc.).
|
|
68
|
+
*/
|
|
69
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
70
|
+
if (event.key !== 'Enter') return
|
|
182
71
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
input.removeAttribute('aria-haspopup')
|
|
188
|
-
input.removeAttribute('aria-expanded')
|
|
189
|
-
// Leave aria-controls untouched to avoid stripping required relationships
|
|
190
|
-
})
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
catch {
|
|
194
|
-
// Do nothing
|
|
72
|
+
event.preventDefault()
|
|
73
|
+
const target = document.activeElement
|
|
74
|
+
if (target instanceof HTMLElement) {
|
|
75
|
+
target.click()
|
|
195
76
|
}
|
|
196
77
|
}
|
|
197
78
|
|
|
198
79
|
/**
|
|
199
|
-
*
|
|
200
|
-
* et réexécuter fixAriaAttributes lorsque nécessaire
|
|
80
|
+
* (Observer désactivé) : on évite de muter globalement les attributs aria du document.
|
|
201
81
|
*/
|
|
202
82
|
const setupMutationObserver = () => {
|
|
203
|
-
//
|
|
204
|
-
if (observer) {
|
|
205
|
-
observer.disconnect()
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Créer un nouvel observateur
|
|
209
|
-
observer = new MutationObserver((mutations) => {
|
|
210
|
-
if (!Array.isArray(mutations)) return
|
|
211
|
-
// Vérifier si les mutations concernent des attributs ARIA ou des éléments pertinents
|
|
212
|
-
const shouldFix = mutations.some((mutation) => {
|
|
213
|
-
if (!mutation) return false
|
|
214
|
-
// Vérification défensive pour s'assurer que mutation.el existe avant d'accéder à ses propriétés
|
|
215
|
-
if (mutation.target === undefined || mutation.target === null) return false
|
|
216
|
-
|
|
217
|
-
// Si un attribut a été modifié
|
|
218
|
-
if (mutation.type === 'attributes') {
|
|
219
|
-
const attributeName = mutation.attributeName
|
|
220
|
-
return attributeName && (
|
|
221
|
-
attributeName.startsWith('aria-')
|
|
222
|
-
|| attributeName === 'class'
|
|
223
|
-
|| attributeName === 'style'
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
// Si des nœuds ont été ajoutés ou supprimés
|
|
227
|
-
return mutation.type === 'childList'
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
// Si des modifications pertinentes ont été détectées, corriger les attributs ARIA
|
|
231
|
-
if (shouldFix) {
|
|
232
|
-
// Utiliser nextTick pour s'assurer que le DOM est stable avant de faire les corrections
|
|
233
|
-
nextTick(() => {
|
|
234
|
-
fixAriaAttributes()
|
|
235
|
-
})
|
|
236
|
-
}
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
// Observer le document entier pour les changements
|
|
240
|
-
observer.observe(document.body, {
|
|
241
|
-
childList: true, // Observer les ajouts/suppressions d'enfants
|
|
242
|
-
subtree: true, // Observer les descendants
|
|
243
|
-
attributes: true, // Observer les changements d'attributs
|
|
244
|
-
attributeFilter: ['aria-expanded', 'aria-haspopup', 'aria-controls', 'class'], // Filtrer les attributs à observer
|
|
245
|
-
})
|
|
83
|
+
// noop
|
|
246
84
|
}
|
|
247
85
|
|
|
248
86
|
// Configurer l'observateur au montage du composant
|
|
@@ -253,12 +91,9 @@ export function useDatePickerAccessibility() {
|
|
|
253
91
|
setupMutationObserver()
|
|
254
92
|
})
|
|
255
93
|
|
|
256
|
-
// Nettoyer l'observateur avant de démonter le composant
|
|
94
|
+
// Nettoyer l'observateur avant de démonter le composant (noop ici)
|
|
257
95
|
onBeforeUnmount(() => {
|
|
258
|
-
|
|
259
|
-
observer.disconnect()
|
|
260
|
-
observer = null
|
|
261
|
-
}
|
|
96
|
+
/* noop */
|
|
262
97
|
})
|
|
263
98
|
|
|
264
99
|
return {
|