@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
|
@@ -3,3 +3,11 @@ export interface IndexedObject<T = string> {
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
export type ValidateOnType = 'lazy' | ('input' | 'blur' | 'submit') | 'input lazy' | 'blur lazy' | 'submit lazy' | 'lazy input' | 'lazy blur' | 'lazy submit' | undefined
|
|
6
|
+
|
|
7
|
+
export interface IDataListItem {
|
|
8
|
+
id: number
|
|
9
|
+
[key: string]: string | number | undefined
|
|
10
|
+
accordionTitle?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type Breakpoints = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'smAndDown' | 'smAndUp' | 'mdAndDown' | 'mdAndUp' | 'lgAndDown' | 'lgAndUp' | 'xlAndDown'
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useDisplay } from 'vuetify'
|
|
4
4
|
import type { ListItem } from './types'
|
|
5
|
-
import { vLetterSpacing } from '@/directives/letterSpacing'
|
|
6
5
|
|
|
7
6
|
const props = defineProps<{
|
|
8
7
|
listTitle: string | null
|
|
@@ -57,7 +56,6 @@
|
|
|
57
56
|
class="vd-collapse-list"
|
|
58
57
|
>
|
|
59
58
|
<h4
|
|
60
|
-
v-letter-spacing
|
|
61
59
|
class="text-subtitle-1 font-weight-bold mb-3"
|
|
62
60
|
>
|
|
63
61
|
{{ listTitle }}
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
import { config } from './config'
|
|
10
10
|
import { locales } from './locales'
|
|
11
11
|
import CookiesSelection from '../CookiesSelection/CookiesSelection.vue'
|
|
12
|
-
import { vLetterSpacing } from '@/directives/letterSpacing'
|
|
13
12
|
|
|
14
13
|
const props = defineProps<CustomizableOptions & {
|
|
15
14
|
items?: CookiesItems
|
|
@@ -167,7 +166,6 @@
|
|
|
167
166
|
>
|
|
168
167
|
<VSheet
|
|
169
168
|
ref="vsheetRef"
|
|
170
|
-
v-letter-spacing
|
|
171
169
|
v-bind="options.banner"
|
|
172
170
|
:aria-label="locales.label"
|
|
173
171
|
class="vd-cookie-banner"
|
|
@@ -179,7 +177,7 @@
|
|
|
179
177
|
>
|
|
180
178
|
<div class="d-flex align-start flex-nowrap pa-0 mb-6">
|
|
181
179
|
<h2
|
|
182
|
-
|
|
180
|
+
|
|
183
181
|
class="text-h5 font-weight-bold"
|
|
184
182
|
>
|
|
185
183
|
{{ locales.title }}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'vue'
|
|
2
|
+
import { ref, onUnmounted } from 'vue'
|
|
3
3
|
import { mdiContentCopy } from '@mdi/js'
|
|
4
4
|
|
|
5
5
|
import useCustomizableOptions, { type CustomizableOptions } from '@/composables/useCustomizableOptions'
|
|
@@ -28,6 +28,13 @@
|
|
|
28
28
|
|
|
29
29
|
const tooltip = ref(false)
|
|
30
30
|
const copyIcon = mdiContentCopy
|
|
31
|
+
let tooltipTimeoutId: ReturnType<typeof setTimeout> | undefined
|
|
32
|
+
|
|
33
|
+
onUnmounted(() => {
|
|
34
|
+
if (tooltipTimeoutId !== undefined) {
|
|
35
|
+
clearTimeout(tooltipTimeoutId)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
31
38
|
|
|
32
39
|
function copy(): void {
|
|
33
40
|
let contentToCopy
|
|
@@ -66,7 +73,7 @@
|
|
|
66
73
|
return
|
|
67
74
|
}
|
|
68
75
|
|
|
69
|
-
setTimeout(() => {
|
|
76
|
+
tooltipTimeoutId = setTimeout(() => {
|
|
70
77
|
tooltip.value = false
|
|
71
78
|
}, props.tooltipDuration)
|
|
72
79
|
}
|
|
@@ -66,6 +66,7 @@ describe('CopyBtn', () => {
|
|
|
66
66
|
propsData: {
|
|
67
67
|
label: 'test',
|
|
68
68
|
textToCopy: 'test',
|
|
69
|
+
tooltipDuration: 100,
|
|
69
70
|
},
|
|
70
71
|
global: {
|
|
71
72
|
plugins: [vuetify],
|
|
@@ -76,7 +77,8 @@ describe('CopyBtn', () => {
|
|
|
76
77
|
|
|
77
78
|
expect(wrapper.vm.tooltip).toBeTruthy()
|
|
78
79
|
|
|
79
|
-
vi.
|
|
80
|
+
vi.advanceTimersByTime(101) // tooltipDuration + 1ms pour être sûr
|
|
81
|
+
|
|
80
82
|
expect(wrapper.vm.tooltip).toBeFalsy()
|
|
81
83
|
})
|
|
82
84
|
|
|
@@ -82,9 +82,16 @@ import AccessibilityIcon from '@/common/imgs/accessibility-svgrepo-com.svg';
|
|
|
82
82
|
</div>
|
|
83
83
|
</div>
|
|
84
84
|
|
|
85
|
+
<div className="accessibility-guide">
|
|
86
|
+
Accessibilité
|
|
87
|
+
=============
|
|
88
|
+
<Story of={AccessStories.Legende} />
|
|
85
89
|
<br />
|
|
90
|
+
|
|
91
|
+
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
86
92
|
<Story of={AccessStories.AccessibilitePanel} />
|
|
87
93
|
<br />
|
|
94
|
+
</div>
|
|
88
95
|
|
|
89
96
|
<style>
|
|
90
97
|
{
|
|
@@ -277,7 +277,10 @@ export const Legende: StoryObj = {
|
|
|
277
277
|
<p style="color: grey; font-size: 14px">Correctifs associés (<a
|
|
278
278
|
href="https://github.com/assurance-maladie-digital/design-system-v3/issues/787" target="_blank"
|
|
279
279
|
style="color:#0C41BD;"
|
|
280
|
-
>issue #787</a
|
|
280
|
+
>issue #787</a>, <a
|
|
281
|
+
href="https://github.com/assurance-maladie-digital/design-system-v3/issues/931" target="_blank"
|
|
282
|
+
style="color:#0C41BD;"
|
|
283
|
+
>issue #931</a>)</p>
|
|
281
284
|
</div>
|
|
282
285
|
</div>
|
|
283
286
|
`,
|
|
@@ -55,6 +55,10 @@ const meta: Meta<typeof SySelect> = {
|
|
|
55
55
|
control: 'text',
|
|
56
56
|
description: 'Permet de définir une largeur personnalisée pour le champ de sélection (en px)',
|
|
57
57
|
},
|
|
58
|
+
helpText: {
|
|
59
|
+
control: 'text',
|
|
60
|
+
description: 'Texte d\'aide à la saisie',
|
|
61
|
+
},
|
|
58
62
|
},
|
|
59
63
|
} as Meta<typeof SySelect>
|
|
60
64
|
|
|
@@ -131,6 +135,80 @@ export const Default: Story = {
|
|
|
131
135
|
},
|
|
132
136
|
}
|
|
133
137
|
|
|
138
|
+
export const HelpText: Story = {
|
|
139
|
+
parameters: {
|
|
140
|
+
sourceCode: [
|
|
141
|
+
{
|
|
142
|
+
name: 'Template',
|
|
143
|
+
code: `
|
|
144
|
+
<template>
|
|
145
|
+
<SySelect
|
|
146
|
+
v-model="value"
|
|
147
|
+
:items="items"
|
|
148
|
+
help-text="Texte d'aide à la saisie"
|
|
149
|
+
/>
|
|
150
|
+
</template>
|
|
151
|
+
`,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'Script',
|
|
155
|
+
code: `
|
|
156
|
+
<script setup lang="ts">
|
|
157
|
+
import SySelect from '@cnamts/SySelect'
|
|
158
|
+
|
|
159
|
+
const items = [
|
|
160
|
+
{ text: 'Adrien', value: 'Adrien' },
|
|
161
|
+
{ text: 'Axel', value: 'Axel' },
|
|
162
|
+
{ text: 'Baptiste', value: 'Baptiste' },
|
|
163
|
+
{ text: 'Clement', value: 'Clement' },
|
|
164
|
+
{ text: 'Corentin', value: 'Corentin' },
|
|
165
|
+
{ text: 'Damien', value: 'Damien' },
|
|
166
|
+
{ text: 'David', value: 'David' },
|
|
167
|
+
{ text: 'Eloi', value: 'Eloi' },
|
|
168
|
+
{ text: 'Louis', value: 'Louis' },
|
|
169
|
+
{ text: 'Valentin', value: 'Valentin' },
|
|
170
|
+
],
|
|
171
|
+
</script>
|
|
172
|
+
`,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
args: {
|
|
177
|
+
'items': [
|
|
178
|
+
{ text: 'Adrien', value: 'Adrien' },
|
|
179
|
+
{ text: 'Axel', value: 'Axel' },
|
|
180
|
+
{ text: 'Baptiste', value: 'Baptiste' },
|
|
181
|
+
{ text: 'Clement', value: 'Clement' },
|
|
182
|
+
{ text: 'Corentin', value: 'Corentin' },
|
|
183
|
+
{ text: 'Damien', value: 'Damien' },
|
|
184
|
+
{ text: 'David', value: 'David' },
|
|
185
|
+
{ text: 'Eloi', value: 'Eloi' },
|
|
186
|
+
{ text: 'Louis', value: 'Louis' },
|
|
187
|
+
{ text: 'Valentin', value: 'Valentin' },
|
|
188
|
+
],
|
|
189
|
+
'helpText': 'Texte d\'aide à la saisie',
|
|
190
|
+
'hideMessages': false,
|
|
191
|
+
'required': true,
|
|
192
|
+
'onUpdate:modelValue': fn(),
|
|
193
|
+
},
|
|
194
|
+
render: (args) => {
|
|
195
|
+
return {
|
|
196
|
+
components: { SySelect, VBtn, VMenu, VList, VListItem, VListItemTitle },
|
|
197
|
+
setup() {
|
|
198
|
+
return { args }
|
|
199
|
+
},
|
|
200
|
+
template: `
|
|
201
|
+
<div class="pa-4">
|
|
202
|
+
<SySelect
|
|
203
|
+
v-bind="args"
|
|
204
|
+
/>
|
|
205
|
+
</div>
|
|
206
|
+
<br/><br/><br/><br/>
|
|
207
|
+
`,
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
|
|
134
212
|
export const Required: Story = {
|
|
135
213
|
parameters: {
|
|
136
214
|
sourceCode: [
|
|
@@ -138,6 +216,7 @@ export const Required: Story = {
|
|
|
138
216
|
name: 'Template',
|
|
139
217
|
code: `
|
|
140
218
|
<template>
|
|
219
|
+
<p class="mb-2 text-caption text-grey-darken-2">Ce champ est obligatoire</p>
|
|
141
220
|
<SySelect
|
|
142
221
|
v-model="value"
|
|
143
222
|
:items="items"
|
|
@@ -177,6 +256,7 @@ export const Required: Story = {
|
|
|
177
256
|
},
|
|
178
257
|
template: `
|
|
179
258
|
<div class="pa-4">
|
|
259
|
+
<p class="mb-2 text-caption text-grey-darken-2">Ce champ est obligatoire</p>
|
|
180
260
|
<SySelect
|
|
181
261
|
v-bind="args"
|
|
182
262
|
:required="args.required"
|
|
@@ -108,6 +108,10 @@
|
|
|
108
108
|
type: Boolean,
|
|
109
109
|
default: false,
|
|
110
110
|
},
|
|
111
|
+
helpText: {
|
|
112
|
+
type: String,
|
|
113
|
+
default: '',
|
|
114
|
+
},
|
|
111
115
|
})
|
|
112
116
|
|
|
113
117
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -120,22 +124,24 @@
|
|
|
120
124
|
const labelWidth = ref(0)
|
|
121
125
|
const labelRef = ref<HTMLElement | null>(null)
|
|
122
126
|
|
|
123
|
-
const toggleMenu = () => {
|
|
127
|
+
const toggleMenu = (skipInitialFocus = false) => {
|
|
124
128
|
if (props.readonly) return
|
|
125
129
|
isOpen.value = !isOpen.value
|
|
126
130
|
if (isOpen.value) {
|
|
127
131
|
updateListPosition()
|
|
128
|
-
// Initialiser la sélection à l'ouverture
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
132
|
+
// Initialiser la sélection à l'ouverture seulement si pas ouvert via clavier
|
|
133
|
+
if (!skipInitialFocus) {
|
|
134
|
+
nextTick(() => {
|
|
135
|
+
// Si un élément est déjà sélectionné, l'activer
|
|
136
|
+
const selectedIndex = formattedItems.value.findIndex(item => isItemSelected(item))
|
|
137
|
+
if (selectedIndex >= 0) {
|
|
138
|
+
setActiveDescendant(selectedIndex)
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
setActiveDescendant(0)
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
}
|
|
139
145
|
}
|
|
140
146
|
}
|
|
141
147
|
|
|
@@ -152,6 +158,8 @@
|
|
|
152
158
|
isOpen.value = false
|
|
153
159
|
}
|
|
154
160
|
const inputId = ref(`sy-select-${Math.random().toString(36).substring(7)}`)
|
|
161
|
+
// Generate unique menu ID for each component instance to avoid conflicts and validation issues
|
|
162
|
+
const uniqueMenuId = ref(props.menuId === 'sy-select-menu' ? `sy-select-menu-${Math.random().toString(36).substring(7)}` : props.menuId)
|
|
155
163
|
const listStyles = ref<Record<string, string>>({})
|
|
156
164
|
const updateListPosition = () => {
|
|
157
165
|
if (input.value?.$el) {
|
|
@@ -357,6 +365,23 @@
|
|
|
357
365
|
|
|
358
366
|
const input = ref<InstanceType<typeof VTextField> | null>(null)
|
|
359
367
|
|
|
368
|
+
// Détecte s'il y a des messages d'erreur, de succès ou d'avertissement
|
|
369
|
+
const hasMessages = computed(() => {
|
|
370
|
+
if (props.disableErrorHandling) return false
|
|
371
|
+
return props.errorMessages.length > 0 || hasError.value
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
// Détermine si le helpText doit être affiché à la position du message ou en dessous
|
|
375
|
+
const showHelpTextAsMessage = computed(() => {
|
|
376
|
+
// Afficher à la position du message si pas de messages d'erreur
|
|
377
|
+
return props.helpText && !hasMessages.value
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
const showHelpTextBelow = computed(() => {
|
|
381
|
+
// Afficher en dessous si il y a des messages d'erreur ET hideMessages n'est pas activé
|
|
382
|
+
return props.helpText && hasMessages.value && !props.hideMessages
|
|
383
|
+
})
|
|
384
|
+
|
|
360
385
|
const calculatedWidth = computed(() => {
|
|
361
386
|
const baseWidth = props.width ? Number(props.width) : 0
|
|
362
387
|
const selectedText = typeof selectedItemText.value === 'string' ? selectedItemText.value : ''
|
|
@@ -378,6 +403,11 @@
|
|
|
378
403
|
handleUpKey,
|
|
379
404
|
handleCharacterKey,
|
|
380
405
|
handleEscapeKey,
|
|
406
|
+
handleHomeKey,
|
|
407
|
+
handleEndKey,
|
|
408
|
+
handlePageUpKey,
|
|
409
|
+
handlePageDownKey,
|
|
410
|
+
handleTabKey,
|
|
381
411
|
restoreFocus,
|
|
382
412
|
} = useSySelectKeyboard({
|
|
383
413
|
isOpen,
|
|
@@ -505,6 +535,59 @@
|
|
|
505
535
|
}
|
|
506
536
|
})
|
|
507
537
|
|
|
538
|
+
let mutationObserver: MutationObserver | null = null
|
|
539
|
+
|
|
540
|
+
// Function to set up proper ARIA attributes
|
|
541
|
+
const setupAriaAttributes = () => {
|
|
542
|
+
if (input.value && input.value.$el) {
|
|
543
|
+
// Find the input element
|
|
544
|
+
const inputElement = input.value.$el?.querySelector?.('input')
|
|
545
|
+
if (inputElement) {
|
|
546
|
+
// Remove problematic attributes that shouldn't be on input
|
|
547
|
+
inputElement.removeAttribute('aria-describedby')
|
|
548
|
+
inputElement.removeAttribute('size')
|
|
549
|
+
inputElement.removeAttribute('tabindex')
|
|
550
|
+
inputElement.removeAttribute('aria-hidden')
|
|
551
|
+
|
|
552
|
+
// Set proper combobox attributes on input element (following CNSA standard)
|
|
553
|
+
inputElement.setAttribute('role', 'combobox')
|
|
554
|
+
inputElement.setAttribute('aria-expanded', isOpen.value ? 'true' : 'false')
|
|
555
|
+
// Only set aria-controls when menu is open and element exists
|
|
556
|
+
if (isOpen.value) {
|
|
557
|
+
inputElement.setAttribute('aria-controls', uniqueMenuId.value)
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
inputElement.removeAttribute('aria-controls')
|
|
561
|
+
}
|
|
562
|
+
// Note: aria-autocomplete is omitted for select-only combobox (invalid to set to 'none')
|
|
563
|
+
inputElement.setAttribute('aria-haspopup', 'listbox')
|
|
564
|
+
if (isOpen.value && activeDescendantId.value) {
|
|
565
|
+
inputElement.setAttribute('aria-activedescendant', activeDescendantId.value)
|
|
566
|
+
}
|
|
567
|
+
if (isRequired.value) {
|
|
568
|
+
inputElement.setAttribute('aria-required', 'true')
|
|
569
|
+
}
|
|
570
|
+
if (hasError.value) {
|
|
571
|
+
inputElement.setAttribute('aria-invalid', 'true')
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Clean up parent element - remove any conflicting attributes
|
|
576
|
+
const parentElement = input.value.$el
|
|
577
|
+
if (parentElement) {
|
|
578
|
+
// Remove any role or ARIA attributes from parent that should be on input
|
|
579
|
+
parentElement.removeAttribute('role')
|
|
580
|
+
parentElement.removeAttribute('aria-expanded')
|
|
581
|
+
parentElement.removeAttribute('aria-controls')
|
|
582
|
+
parentElement.removeAttribute('aria-haspopup')
|
|
583
|
+
parentElement.removeAttribute('aria-activedescendant')
|
|
584
|
+
parentElement.removeAttribute('aria-required')
|
|
585
|
+
parentElement.removeAttribute('aria-invalid')
|
|
586
|
+
parentElement.removeAttribute('aria-hidden')
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
508
591
|
onMounted(() => {
|
|
509
592
|
if (labelRef.value) {
|
|
510
593
|
labelWidth.value = labelRef.value.offsetWidth + 64
|
|
@@ -513,25 +596,158 @@
|
|
|
513
596
|
window.addEventListener('resize', updateListPosition)
|
|
514
597
|
|
|
515
598
|
// Use nextTick to ensure the DOM is fully rendered
|
|
599
|
+
nextTick(() => {
|
|
600
|
+
// Initial setup
|
|
601
|
+
setupAriaAttributes()
|
|
602
|
+
|
|
603
|
+
// Set up MutationObserver to monitor attribute changes
|
|
604
|
+
if (input.value && input.value.$el) {
|
|
605
|
+
mutationObserver = new MutationObserver((mutations) => {
|
|
606
|
+
let needsCleanup = false
|
|
607
|
+
mutations.forEach((mutation) => {
|
|
608
|
+
if (mutation.type === 'attributes') {
|
|
609
|
+
const target = mutation.target as HTMLElement
|
|
610
|
+
const attributeName = mutation.attributeName
|
|
611
|
+
|
|
612
|
+
// Check if problematic attributes were added to input
|
|
613
|
+
if (target.tagName === 'INPUT' && (
|
|
614
|
+
attributeName === 'role'
|
|
615
|
+
|| attributeName === 'aria-hidden'
|
|
616
|
+
|| attributeName === 'aria-expanded'
|
|
617
|
+
|| attributeName === 'aria-controls'
|
|
618
|
+
|| attributeName === 'aria-haspopup'
|
|
619
|
+
)) {
|
|
620
|
+
needsCleanup = true
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Check if aria-hidden was added to parent
|
|
624
|
+
if (target === input.value?.$el && attributeName === 'aria-hidden') {
|
|
625
|
+
needsCleanup = true
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
})
|
|
629
|
+
|
|
630
|
+
if (needsCleanup) {
|
|
631
|
+
// Use setTimeout to avoid infinite loops
|
|
632
|
+
setTimeout(setupAriaAttributes, 0)
|
|
633
|
+
}
|
|
634
|
+
})
|
|
635
|
+
|
|
636
|
+
// Observe both the parent element and its children
|
|
637
|
+
mutationObserver.observe(input.value.$el, {
|
|
638
|
+
attributes: true,
|
|
639
|
+
subtree: true,
|
|
640
|
+
attributeFilter: ['role', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-haspopup'],
|
|
641
|
+
})
|
|
642
|
+
}
|
|
643
|
+
})
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
// Watchers to update ARIA attributes dynamically on input element
|
|
647
|
+
watch(isOpen, (newValue) => {
|
|
516
648
|
nextTick(() => {
|
|
517
649
|
if (input.value && input.value.$el) {
|
|
518
|
-
|
|
519
|
-
const inputElement = input.value.$el.querySelector('input')
|
|
650
|
+
const inputElement = input.value.$el?.querySelector?.('input')
|
|
520
651
|
if (inputElement) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
652
|
+
inputElement.setAttribute('aria-expanded', newValue ? 'true' : 'false')
|
|
653
|
+
if (newValue && activeDescendantId.value) {
|
|
654
|
+
inputElement.setAttribute('aria-activedescendant', activeDescendantId.value)
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
657
|
+
inputElement.removeAttribute('aria-activedescendant')
|
|
658
|
+
}
|
|
527
659
|
}
|
|
528
660
|
}
|
|
529
661
|
})
|
|
530
662
|
})
|
|
531
663
|
|
|
664
|
+
watch(activeDescendantId, (newValue) => {
|
|
665
|
+
nextTick(() => {
|
|
666
|
+
if (input.value && input.value.$el && isOpen.value) {
|
|
667
|
+
const inputElement = input.value.$el?.querySelector?.('input')
|
|
668
|
+
if (inputElement) {
|
|
669
|
+
if (newValue) {
|
|
670
|
+
inputElement.setAttribute('aria-activedescendant', newValue)
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
inputElement.removeAttribute('aria-activedescendant')
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
})
|
|
678
|
+
})
|
|
679
|
+
|
|
680
|
+
watch(hasError, (newValue) => {
|
|
681
|
+
nextTick(() => {
|
|
682
|
+
if (input.value && input.value.$el) {
|
|
683
|
+
const inputElement = input.value.$el?.querySelector?.('input')
|
|
684
|
+
if (inputElement) {
|
|
685
|
+
if (newValue) {
|
|
686
|
+
inputElement.setAttribute('aria-invalid', 'true')
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
inputElement.removeAttribute('aria-invalid')
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
})
|
|
694
|
+
})
|
|
695
|
+
|
|
696
|
+
// Watch for selection changes to enforce correct accessibility attributes
|
|
697
|
+
// This prevents Vuetify from overriding our combobox attributes
|
|
698
|
+
watch(selectedItem, () => {
|
|
699
|
+
nextTick(() => {
|
|
700
|
+
if (input.value && input.value.$el) {
|
|
701
|
+
const inputElement = input.value.$el?.querySelector?.('input')
|
|
702
|
+
if (inputElement) {
|
|
703
|
+
// Ensure combobox role is maintained on input
|
|
704
|
+
inputElement.setAttribute('role', 'combobox')
|
|
705
|
+
// Ensure aria-hidden is never set to true
|
|
706
|
+
inputElement.removeAttribute('aria-hidden')
|
|
707
|
+
// Maintain other combobox attributes
|
|
708
|
+
inputElement.setAttribute('aria-expanded', isOpen.value ? 'true' : 'false')
|
|
709
|
+
inputElement.setAttribute('aria-haspopup', 'listbox')
|
|
710
|
+
// Note: aria-autocomplete is omitted for select-only combobox
|
|
711
|
+
// Only set aria-controls when menu is open and element exists
|
|
712
|
+
if (isOpen.value) {
|
|
713
|
+
inputElement.setAttribute('aria-controls', uniqueMenuId.value)
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
inputElement.removeAttribute('aria-controls')
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Only add aria-required if the component is actually required
|
|
720
|
+
if (isRequired.value) {
|
|
721
|
+
inputElement.setAttribute('aria-required', 'true')
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
inputElement.removeAttribute('aria-required')
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Clean up parent element
|
|
729
|
+
const parentElement = input.value.$el
|
|
730
|
+
if (parentElement) {
|
|
731
|
+
parentElement.removeAttribute('role')
|
|
732
|
+
parentElement.removeAttribute('aria-hidden')
|
|
733
|
+
parentElement.removeAttribute('aria-expanded')
|
|
734
|
+
parentElement.removeAttribute('aria-haspopup')
|
|
735
|
+
parentElement.removeAttribute('aria-controls')
|
|
736
|
+
parentElement.removeAttribute('aria-required')
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
})
|
|
740
|
+
}, { deep: true })
|
|
741
|
+
|
|
532
742
|
onUnmounted(() => {
|
|
533
743
|
window.removeEventListener('scroll', updateListPosition, true)
|
|
534
744
|
window.removeEventListener('resize', updateListPosition)
|
|
745
|
+
|
|
746
|
+
// Clean up MutationObserver
|
|
747
|
+
if (mutationObserver) {
|
|
748
|
+
mutationObserver.disconnect()
|
|
749
|
+
mutationObserver = null
|
|
750
|
+
}
|
|
535
751
|
})
|
|
536
752
|
|
|
537
753
|
defineExpose({
|
|
@@ -549,27 +765,19 @@
|
|
|
549
765
|
v-rgaa-svg-fix="true"
|
|
550
766
|
:title="$attrs['aria-label'] || labelWithAsterisk"
|
|
551
767
|
color="primary"
|
|
552
|
-
role="combobox"
|
|
553
768
|
:disabled="disabled"
|
|
554
769
|
:label="labelWithAsterisk"
|
|
555
770
|
:aria-label="$attrs['aria-label'] || labelWithAsterisk"
|
|
556
|
-
:aria-expanded="isOpen ? 'true' : 'false'"
|
|
557
|
-
:aria-controls="menuId"
|
|
558
|
-
aria-autocomplete="list"
|
|
559
|
-
aria-haspopup="listbox"
|
|
560
|
-
aria-readonly="true"
|
|
561
|
-
:aria-owns="menuId"
|
|
562
|
-
:aria-activedescendant="isOpen ? activeDescendantId : undefined"
|
|
563
771
|
:error-messages="props.disableErrorHandling ? [] : errorMessages"
|
|
564
772
|
:variant="outlined ? 'outlined' : 'underlined'"
|
|
565
773
|
:rules="isRequired && !props.disableErrorHandling ? ['Le champ est requis.'] : []"
|
|
566
|
-
:aria-required="isRequired ? 'true' : undefined"
|
|
567
|
-
:aria-invalid="hasError ? 'true' : undefined"
|
|
568
774
|
:bg-color="props.bgColor"
|
|
569
775
|
:density="props.density"
|
|
570
776
|
:active="hasChips || isOpen"
|
|
571
777
|
readonly
|
|
572
|
-
:hide-details="props.hideMessages"
|
|
778
|
+
:hide-details="props.hideMessages && !showHelpTextAsMessage"
|
|
779
|
+
:hint="showHelpTextAsMessage ? props.helpText : ''"
|
|
780
|
+
:persistent-hint="!!showHelpTextAsMessage"
|
|
573
781
|
class="sy-select"
|
|
574
782
|
:width="calculatedWidth"
|
|
575
783
|
:style="hasError ? { minWidth: `${labelWidth + 18}px`} : {minWidth: `${labelWidth}px`}"
|
|
@@ -580,6 +788,11 @@
|
|
|
580
788
|
@keydown.down.prevent="handleDownKey"
|
|
581
789
|
@keydown.up.prevent="handleUpKey"
|
|
582
790
|
@keydown.esc.prevent="handleEscapeKey"
|
|
791
|
+
@keydown.home.prevent="handleHomeKey"
|
|
792
|
+
@keydown.end.prevent="handleEndKey"
|
|
793
|
+
@keydown.page-up.prevent="handlePageUpKey"
|
|
794
|
+
@keydown.page-down.prevent="handlePageDownKey"
|
|
795
|
+
@keydown.tab="handleTabKey"
|
|
583
796
|
@keydown="(e) => {
|
|
584
797
|
// Handle printable characters for keyboard navigation
|
|
585
798
|
if (!e.ctrlKey && !e.altKey && !e.metaKey) {
|
|
@@ -607,6 +820,7 @@
|
|
|
607
820
|
<SyIcon
|
|
608
821
|
v-if="hasError"
|
|
609
822
|
class="mr-6"
|
|
823
|
+
color="error"
|
|
610
824
|
:icon="mdiInformation"
|
|
611
825
|
:decorative="false"
|
|
612
826
|
label="Information"
|
|
@@ -641,7 +855,7 @@
|
|
|
641
855
|
>{{ label }}</span>
|
|
642
856
|
<VList
|
|
643
857
|
v-if="isOpen"
|
|
644
|
-
:id="
|
|
858
|
+
:id="uniqueMenuId"
|
|
645
859
|
class="v-list"
|
|
646
860
|
role="listbox"
|
|
647
861
|
:aria-multiselectable="props.multiple ? 'true' : undefined"
|
|
@@ -654,10 +868,14 @@
|
|
|
654
868
|
tabindex="0"
|
|
655
869
|
:title="props.multiple ? 'Sélection multiple' : 'Sélection'"
|
|
656
870
|
@keydown.esc.prevent="closeList"
|
|
657
|
-
@keydown.tab
|
|
871
|
+
@keydown.tab="handleTabKey"
|
|
658
872
|
@keydown.enter.prevent="handleEnterKey"
|
|
659
873
|
@keydown.down.prevent="handleDownKey"
|
|
660
874
|
@keydown.up.prevent="handleUpKey"
|
|
875
|
+
@keydown.home.prevent="handleHomeKey"
|
|
876
|
+
@keydown.end.prevent="handleEndKey"
|
|
877
|
+
@keydown.page-up.prevent="handlePageUpKey"
|
|
878
|
+
@keydown.page-down.prevent="handlePageDownKey"
|
|
661
879
|
@click.stop
|
|
662
880
|
>
|
|
663
881
|
<VListItem
|
|
@@ -667,7 +885,7 @@
|
|
|
667
885
|
:ref="'options-' + index"
|
|
668
886
|
role="option"
|
|
669
887
|
class="v-list-item"
|
|
670
|
-
:aria-selected="
|
|
888
|
+
:aria-selected="isItemSelected(item) ? 'true' : 'false'"
|
|
671
889
|
tabindex="-1"
|
|
672
890
|
:class="{ active: isItemSelected(item) || `option-${index}` === activeDescendantId }"
|
|
673
891
|
@click.stop="(event) => selectItem(item, event)"
|
|
@@ -692,6 +910,14 @@
|
|
|
692
910
|
</VListItemTitle>
|
|
693
911
|
</VListItem>
|
|
694
912
|
</VList>
|
|
913
|
+
|
|
914
|
+
<div
|
|
915
|
+
v-if="showHelpTextBelow"
|
|
916
|
+
class="help-text-below px-4 mt-1"
|
|
917
|
+
:class="{ 'text-disabled': props.disabled }"
|
|
918
|
+
>
|
|
919
|
+
{{ props.helpText }}
|
|
920
|
+
</div>
|
|
695
921
|
</template>
|
|
696
922
|
|
|
697
923
|
<style scoped lang="scss">
|
|
@@ -734,6 +960,26 @@
|
|
|
734
960
|
background-color: rgb(0 0 0 / 8%);
|
|
735
961
|
}
|
|
736
962
|
|
|
963
|
+
.help-text {
|
|
964
|
+
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
965
|
+
font-size: 14px;
|
|
966
|
+
line-height: 1.2;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
.help-text.text-disabled {
|
|
970
|
+
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
.help-text-below {
|
|
974
|
+
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
975
|
+
font-size: 14px;
|
|
976
|
+
line-height: 1.2;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.help-text-below.text-disabled {
|
|
980
|
+
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
|
981
|
+
}
|
|
982
|
+
|
|
737
983
|
/* Ensure focus styles match selection styles for keyboard navigation */
|
|
738
984
|
.v-list-item:focus-visible,
|
|
739
985
|
.v-list-item.keyboard-focused {
|