@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
|
@@ -34,6 +34,14 @@ const meta: Meta<typeof SySelect> = {
|
|
|
34
34
|
control: 'boolean',
|
|
35
35
|
description: 'Permet de vider la sélection',
|
|
36
36
|
},
|
|
37
|
+
multiple: {
|
|
38
|
+
control: 'boolean',
|
|
39
|
+
description: 'Permet la sélection multiple d\'options',
|
|
40
|
+
},
|
|
41
|
+
chips: {
|
|
42
|
+
control: 'boolean',
|
|
43
|
+
description: 'Affiche les options sélectionnées sous forme de chips',
|
|
44
|
+
},
|
|
37
45
|
hideMessages: {
|
|
38
46
|
control: 'boolean',
|
|
39
47
|
description: 'Masque les messages d\'erreur',
|
|
@@ -228,6 +236,158 @@ const items = [
|
|
|
228
236
|
},
|
|
229
237
|
}
|
|
230
238
|
|
|
239
|
+
export const MultipleSelection: Story = {
|
|
240
|
+
parameters: {
|
|
241
|
+
docs: {
|
|
242
|
+
description: {
|
|
243
|
+
story: 'Exemple de sélection multiple avec SySelect. Les options dans le menu déroulant sont affichées avec des cases à cocher pour faciliter la sélection multiple.',
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
sourceCode: [
|
|
247
|
+
{
|
|
248
|
+
name: 'Template',
|
|
249
|
+
code: `
|
|
250
|
+
<template>
|
|
251
|
+
<SySelect
|
|
252
|
+
v-model="selectedOptions"
|
|
253
|
+
:items="options"
|
|
254
|
+
label="Options"
|
|
255
|
+
multiple
|
|
256
|
+
/>
|
|
257
|
+
<div class="mt-4">
|
|
258
|
+
Options sélectionnées: {{ selectedOptions }}
|
|
259
|
+
</div>
|
|
260
|
+
</template>
|
|
261
|
+
`,
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: 'Script',
|
|
265
|
+
code: `
|
|
266
|
+
<script setup lang="ts">
|
|
267
|
+
import { ref } from 'vue'
|
|
268
|
+
import SySelect from '@cnamts/synapse'
|
|
269
|
+
|
|
270
|
+
const selectedOptions = ref([])
|
|
271
|
+
const options = [
|
|
272
|
+
{ text: 'Option 1', value: '1' },
|
|
273
|
+
{ text: 'Option 2', value: '2' },
|
|
274
|
+
{ text: 'Option 3', value: '3' },
|
|
275
|
+
{ text: 'Option 4', value: '4' },
|
|
276
|
+
]
|
|
277
|
+
</script>
|
|
278
|
+
`,
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
},
|
|
282
|
+
args: {
|
|
283
|
+
'items': [
|
|
284
|
+
{ text: 'Option 1', value: '1' },
|
|
285
|
+
{ text: 'Option 2', value: '2' },
|
|
286
|
+
{ text: 'Option 3', value: '3' },
|
|
287
|
+
{ text: 'Option 4', value: '4' },
|
|
288
|
+
],
|
|
289
|
+
'label': 'Sélection multiple',
|
|
290
|
+
'multiple': true,
|
|
291
|
+
'clearable': true,
|
|
292
|
+
'onUpdate:modelValue': fn(),
|
|
293
|
+
},
|
|
294
|
+
render: (args) => {
|
|
295
|
+
return {
|
|
296
|
+
components: { SySelect },
|
|
297
|
+
setup() {
|
|
298
|
+
const selectedOptions = ref([])
|
|
299
|
+
|
|
300
|
+
return { args, selectedOptions }
|
|
301
|
+
},
|
|
302
|
+
template: `
|
|
303
|
+
<div class="pa-4">
|
|
304
|
+
<SySelect
|
|
305
|
+
v-model="selectedOptions"
|
|
306
|
+
v-bind="args"
|
|
307
|
+
/>
|
|
308
|
+
<div class="mt-4">
|
|
309
|
+
Options sélectionnées: {{ selectedOptions }}
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
`,
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export const ChipsDisplay: Story = {
|
|
318
|
+
parameters: {
|
|
319
|
+
docs: {
|
|
320
|
+
description: {
|
|
321
|
+
story: 'Exemple de sélection multiple avec affichage en chips. Les options sélectionnées sont affichées sous forme de chips dans le champ, et les options dans le menu déroulant sont affichées avec des cases à cocher.',
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
sourceCode: [
|
|
325
|
+
{
|
|
326
|
+
name: 'Template',
|
|
327
|
+
code: `
|
|
328
|
+
<template>
|
|
329
|
+
<SySelect
|
|
330
|
+
v-model="selectedOptions"
|
|
331
|
+
:items="options"
|
|
332
|
+
label="Options"
|
|
333
|
+
multiple
|
|
334
|
+
chips
|
|
335
|
+
/>
|
|
336
|
+
</template>
|
|
337
|
+
`,
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: 'Script',
|
|
341
|
+
code: `
|
|
342
|
+
<script setup lang="ts">
|
|
343
|
+
import { ref } from 'vue'
|
|
344
|
+
import SySelect from '@cnamts/synapse'
|
|
345
|
+
|
|
346
|
+
const selectedOptions = ref([])
|
|
347
|
+
const options = [
|
|
348
|
+
{ text: 'Option 1', value: '1' },
|
|
349
|
+
{ text: 'Option 2', value: '2' },
|
|
350
|
+
{ text: 'Option 3', value: '3' },
|
|
351
|
+
{ text: 'Option 4', value: '4' },
|
|
352
|
+
]
|
|
353
|
+
</script>
|
|
354
|
+
`,
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
},
|
|
358
|
+
args: {
|
|
359
|
+
'items': [
|
|
360
|
+
{ text: 'Option 1', value: '1' },
|
|
361
|
+
{ text: 'Option 2', value: '2' },
|
|
362
|
+
{ text: 'Option 3', value: '3' },
|
|
363
|
+
{ text: 'Option 4', value: '4' },
|
|
364
|
+
],
|
|
365
|
+
'label': 'Sélection avec chips',
|
|
366
|
+
'multiple': true,
|
|
367
|
+
'chips': true,
|
|
368
|
+
'clearable': true,
|
|
369
|
+
'onUpdate:modelValue': fn(),
|
|
370
|
+
},
|
|
371
|
+
render: (args) => {
|
|
372
|
+
return {
|
|
373
|
+
components: { SySelect },
|
|
374
|
+
setup() {
|
|
375
|
+
const selectedOptions = ref([])
|
|
376
|
+
|
|
377
|
+
return { args, selectedOptions }
|
|
378
|
+
},
|
|
379
|
+
template: `
|
|
380
|
+
<div class="pa-4">
|
|
381
|
+
<SySelect
|
|
382
|
+
v-model="selectedOptions"
|
|
383
|
+
v-bind="args"
|
|
384
|
+
/>
|
|
385
|
+
</div>
|
|
386
|
+
`,
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
}
|
|
390
|
+
|
|
231
391
|
export const withCustomError: Story = {
|
|
232
392
|
parameters: {
|
|
233
393
|
sourceCode: [
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
// Prevent display-asterisk from being passed to the DOM
|
|
3
|
+
defineOptions({
|
|
4
|
+
inheritAttrs: false,
|
|
5
|
+
})
|
|
2
6
|
import { mdiInformation, mdiMenuDown, mdiCloseCircle } from '@mdi/js'
|
|
3
|
-
import { ref, watch, onMounted, onUnmounted, computed, type PropType } from 'vue'
|
|
7
|
+
import { ref, watch, onMounted, onUnmounted, computed, nextTick, type PropType } from 'vue'
|
|
4
8
|
import type { VTextField } from 'vuetify/components'
|
|
9
|
+
import { VChip, VCheckbox } from 'vuetify/components'
|
|
5
10
|
import { locales } from './locales'
|
|
6
11
|
|
|
7
12
|
export type ItemType = {
|
|
8
13
|
[key: string]: unknown
|
|
9
14
|
}
|
|
10
15
|
|
|
16
|
+
export type SelectItemValueType = Record<string, unknown> | string | number | null | undefined
|
|
17
|
+
export type SelectItemArrayType = Array<Record<string, unknown> | string | number>
|
|
18
|
+
|
|
19
|
+
// Définition des props avec typage correct pour modelValue
|
|
11
20
|
const props = defineProps({
|
|
12
21
|
modelValue: {
|
|
13
|
-
|
|
22
|
+
// En Vue, on ne peut pas mettre null directement comme type
|
|
23
|
+
// On utilise PropType pour définir le type complet incluant null
|
|
24
|
+
type: [Object, String, Number, Array] as PropType<Record<string, unknown> | string | number | null | SelectItemArrayType>,
|
|
14
25
|
default: null,
|
|
15
26
|
},
|
|
16
27
|
items: {
|
|
@@ -67,7 +78,7 @@
|
|
|
67
78
|
},
|
|
68
79
|
bgColor: {
|
|
69
80
|
type: String,
|
|
70
|
-
default:
|
|
81
|
+
default: 'white',
|
|
71
82
|
},
|
|
72
83
|
readonly: {
|
|
73
84
|
type: Boolean,
|
|
@@ -85,12 +96,21 @@
|
|
|
85
96
|
type: String,
|
|
86
97
|
default: 'undefined',
|
|
87
98
|
},
|
|
99
|
+
multiple: {
|
|
100
|
+
type: Boolean,
|
|
101
|
+
default: false,
|
|
102
|
+
},
|
|
103
|
+
chips: {
|
|
104
|
+
type: Boolean,
|
|
105
|
+
default: false,
|
|
106
|
+
},
|
|
88
107
|
})
|
|
89
108
|
|
|
90
109
|
const emit = defineEmits(['update:modelValue'])
|
|
91
110
|
|
|
92
111
|
const isOpen = ref(false)
|
|
93
|
-
|
|
112
|
+
// Initialize selectedItem with props.modelValue or empty array for multiple mode
|
|
113
|
+
const selectedItem = ref<SelectItemValueType | SelectItemArrayType>(props.modelValue)
|
|
94
114
|
const hasError = ref(false)
|
|
95
115
|
|
|
96
116
|
const labelWidth = ref(0)
|
|
@@ -101,7 +121,16 @@
|
|
|
101
121
|
isOpen.value = !isOpen.value
|
|
102
122
|
if (isOpen.value) updateListPosition()
|
|
103
123
|
}
|
|
104
|
-
const closeList = () => {
|
|
124
|
+
const closeList = (event?: Event) => {
|
|
125
|
+
// Check if the click is inside the dropdown list
|
|
126
|
+
const target = event?.target as HTMLElement
|
|
127
|
+
const listElement = document.querySelector('.v-list')
|
|
128
|
+
|
|
129
|
+
// In multiple selection mode, don't close the dropdown when clicking on list items
|
|
130
|
+
if (props.multiple && listElement && listElement.contains(target)) {
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
105
134
|
isOpen.value = false
|
|
106
135
|
}
|
|
107
136
|
const inputId = ref(`sy-select-${Math.random().toString(36).substring(7)}`)
|
|
@@ -119,21 +148,78 @@
|
|
|
119
148
|
}
|
|
120
149
|
}
|
|
121
150
|
|
|
122
|
-
|
|
123
|
-
|
|
151
|
+
const selectItem = (item: ItemType | null, event?: Event) => {
|
|
152
|
+
// Stop event propagation to prevent click-outside from triggering
|
|
153
|
+
event?.stopPropagation()
|
|
154
|
+
|
|
124
155
|
if (item === null) {
|
|
125
|
-
selectedItem.value = null
|
|
126
|
-
emit('update:modelValue', null)
|
|
156
|
+
selectedItem.value = props.multiple ? [] : null
|
|
157
|
+
emit('update:modelValue', props.multiple ? [] : null)
|
|
158
|
+
isOpen.value = false
|
|
159
|
+
return
|
|
127
160
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
161
|
+
|
|
162
|
+
// Handle default option in multiple mode
|
|
163
|
+
if (props.multiple && isDefaultOption(item)) {
|
|
164
|
+
// Clicking the default option in multiple mode clears all selections
|
|
165
|
+
selectedItem.value = []
|
|
166
|
+
emit('update:modelValue', [])
|
|
167
|
+
isOpen.value = false
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (props.multiple) {
|
|
172
|
+
// Initialize as empty array if not already an array
|
|
173
|
+
if (!Array.isArray(selectedItem.value)) {
|
|
174
|
+
selectedItem.value = []
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const selectedArray = selectedItem.value as SelectItemArrayType
|
|
178
|
+
let valueToCheck: unknown
|
|
179
|
+
let valueToStore: Record<string, unknown> | string | number
|
|
180
|
+
|
|
181
|
+
if (props.returnObject) {
|
|
182
|
+
valueToCheck = item[props.valueKey]
|
|
183
|
+
valueToStore = item
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
valueToCheck = item[props.valueKey]
|
|
187
|
+
valueToStore = item[props.valueKey] as string | number | Record<string, unknown>
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Check if item is already selected
|
|
191
|
+
const index = selectedArray.findIndex((selected) => {
|
|
192
|
+
if (props.returnObject) {
|
|
193
|
+
return selected[props.valueKey] === valueToCheck
|
|
194
|
+
}
|
|
195
|
+
return selected === valueToCheck
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// Toggle selection
|
|
199
|
+
if (index > -1) {
|
|
200
|
+
selectedArray.splice(index, 1)
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
selectedArray.push(valueToStore)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
emit('update:modelValue', [...selectedArray])
|
|
207
|
+
// Keep dropdown open for multiple selection
|
|
208
|
+
isOpen.value = true
|
|
131
209
|
}
|
|
132
210
|
else {
|
|
133
|
-
|
|
134
|
-
|
|
211
|
+
// Single selection mode
|
|
212
|
+
if (props.returnObject) {
|
|
213
|
+
selectedItem.value = item
|
|
214
|
+
emit('update:modelValue', item)
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
selectedItem.value = item[props.valueKey] as SelectItemValueType
|
|
218
|
+
emit('update:modelValue', item[props.valueKey] as SelectItemValueType)
|
|
219
|
+
}
|
|
220
|
+
// Close dropdown for single selection
|
|
221
|
+
isOpen.value = false
|
|
135
222
|
}
|
|
136
|
-
isOpen.value = false
|
|
137
223
|
}
|
|
138
224
|
|
|
139
225
|
const getItemText = (item: unknown) => {
|
|
@@ -142,18 +228,50 @@
|
|
|
142
228
|
}
|
|
143
229
|
|
|
144
230
|
const selectedItemText = computed(() => {
|
|
145
|
-
|
|
231
|
+
// If chips are enabled and we have selected items, return empty string to hide text
|
|
232
|
+
if (hasChips.value) {
|
|
233
|
+
return ''
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// For multiple mode, show default option text when nothing is selected
|
|
237
|
+
if (props.multiple) {
|
|
238
|
+
if (!selectedItem.value || (Array.isArray(selectedItem.value) && selectedItem.value.length === 0)) {
|
|
239
|
+
// Find default option and return its text
|
|
240
|
+
const defaultOption = props.items.find(item => isDefaultOption(item))
|
|
241
|
+
if (defaultOption) {
|
|
242
|
+
return defaultOption[props.textKey] as string
|
|
243
|
+
}
|
|
244
|
+
return ''
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// For multiple selection with items selected, return an array of text values
|
|
248
|
+
const selectedArray = selectedItem.value as SelectItemArrayType
|
|
249
|
+
|
|
250
|
+
return selectedArray.map((selected) => {
|
|
251
|
+
if (props.returnObject) {
|
|
252
|
+
return selected?.[props.textKey]
|
|
253
|
+
}
|
|
254
|
+
return props.items.find((item: ItemType) => item[props.valueKey] === selected)?.[props.textKey] || ''
|
|
255
|
+
}).join(', ')
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// For single selection
|
|
259
|
+
if (!selectedItem.value) return ''
|
|
260
|
+
|
|
146
261
|
if (props.returnObject) {
|
|
147
|
-
return
|
|
262
|
+
return selectedItem.value[props.textKey]
|
|
148
263
|
}
|
|
149
|
-
|
|
150
|
-
return props.items.find(
|
|
264
|
+
|
|
265
|
+
return props.items.find(item => item[props.valueKey] === selectedItem.value)?.[props.textKey] || ''
|
|
151
266
|
}
|
|
152
|
-
return ''
|
|
153
267
|
})
|
|
154
268
|
|
|
155
269
|
const isShouldDisplayAsterisk = computed(() => {
|
|
156
|
-
return props.
|
|
270
|
+
return props.required && props.displayAsterisk
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
const hasChips = computed(() => {
|
|
274
|
+
return props.chips && props.multiple && Array.isArray(selectedItem.value) && selectedItem.value.length > 0
|
|
157
275
|
})
|
|
158
276
|
|
|
159
277
|
const labelWithAsterisk = computed(() => {
|
|
@@ -188,6 +306,103 @@
|
|
|
188
306
|
selectedItem.value = newValue
|
|
189
307
|
})
|
|
190
308
|
|
|
309
|
+
// Function to check if an item is the default option (e.g., "-choisir-")
|
|
310
|
+
const isDefaultOption = (item: ItemType) => {
|
|
311
|
+
// Check if this is the first item and has a placeholder-like text
|
|
312
|
+
const itemText = item[props.textKey] as string
|
|
313
|
+
return itemText.includes('-') && (itemText.includes('choisir') || itemText.includes('sélectionner'))
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Function to check if an item is selected
|
|
317
|
+
const isItemSelected = (item: ItemType) => {
|
|
318
|
+
// For default option in multiple mode, show as selected when no other items are selected
|
|
319
|
+
if (props.multiple && isDefaultOption(item)) {
|
|
320
|
+
return !selectedItem.value || (Array.isArray(selectedItem.value) && selectedItem.value.length === 0)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!selectedItem.value) return false
|
|
324
|
+
|
|
325
|
+
if (props.multiple && Array.isArray(selectedItem.value)) {
|
|
326
|
+
return selectedItem.value.some((selected) => {
|
|
327
|
+
if (props.returnObject) {
|
|
328
|
+
return selected?.[props.valueKey] === item?.[props.valueKey]
|
|
329
|
+
}
|
|
330
|
+
return selected === item?.[props.valueKey]
|
|
331
|
+
})
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
if (props.returnObject) {
|
|
335
|
+
return Boolean(selectedItem.value && selectedItem.value[props.valueKey] === item?.[props.valueKey])
|
|
336
|
+
}
|
|
337
|
+
return selectedItem.value === item?.[props.valueKey]
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Function to safely get an item for chip operations
|
|
342
|
+
const safeChipItem = (item: unknown): Record<string, unknown> | string | number => {
|
|
343
|
+
// Handle null/undefined case
|
|
344
|
+
if (item === null || item === undefined) return ''
|
|
345
|
+
|
|
346
|
+
// If it's already a valid type, return it
|
|
347
|
+
if (typeof item === 'string' || typeof item === 'number') return item
|
|
348
|
+
|
|
349
|
+
// If it's an object, return it as a Record
|
|
350
|
+
if (typeof item === 'object') return item as Record<string, unknown>
|
|
351
|
+
|
|
352
|
+
// Default case - convert to string
|
|
353
|
+
return String(item)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Function to get text for a chip
|
|
357
|
+
const getChipText = (item: unknown) => {
|
|
358
|
+
const safeItem = safeChipItem(item)
|
|
359
|
+
|
|
360
|
+
if (typeof safeItem === 'object') {
|
|
361
|
+
// Handle object type
|
|
362
|
+
return (safeItem as Record<string, unknown>)[props.textKey] as string
|
|
363
|
+
}
|
|
364
|
+
// Handle primitive types
|
|
365
|
+
return props.items.find((i: ItemType) => i[props.valueKey] === safeItem)?.[props.textKey] as string || ''
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Function to remove a chip
|
|
369
|
+
const removeChip = (item: unknown) => {
|
|
370
|
+
if (!Array.isArray(selectedItem.value)) return
|
|
371
|
+
|
|
372
|
+
const selectedArray = [...selectedItem.value] // Create a copy to avoid mutation issues
|
|
373
|
+
const safeItem = safeChipItem(item)
|
|
374
|
+
let index: number
|
|
375
|
+
|
|
376
|
+
if (props.returnObject) {
|
|
377
|
+
// Handle object type
|
|
378
|
+
const itemValue = typeof safeItem === 'object'
|
|
379
|
+
? (safeItem as Record<string, unknown>)[props.valueKey]
|
|
380
|
+
: safeItem
|
|
381
|
+
index = selectedArray.findIndex(selected =>
|
|
382
|
+
(selected as Record<string, unknown>)[props.valueKey] === itemValue)
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
index = selectedArray.indexOf(safeItem)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (index > -1) {
|
|
389
|
+
selectedArray.splice(index, 1)
|
|
390
|
+
// Ensure reactivity by creating a completely new array
|
|
391
|
+
const updatedArray = [...selectedArray]
|
|
392
|
+
|
|
393
|
+
// Update the local state first
|
|
394
|
+
selectedItem.value = updatedArray
|
|
395
|
+
|
|
396
|
+
// Then emit the update to the parent
|
|
397
|
+
emit('update:modelValue', updatedArray)
|
|
398
|
+
|
|
399
|
+
// Force update of the UI
|
|
400
|
+
nextTick(() => {
|
|
401
|
+
updateListPosition()
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
191
406
|
watch([isOpen, hasError], ([newIsOpen, newHasError]) => {
|
|
192
407
|
if (!newIsOpen) {
|
|
193
408
|
if (props.disableErrorHandling || props.readonly) {
|
|
@@ -218,6 +433,18 @@
|
|
|
218
433
|
}
|
|
219
434
|
window.addEventListener('scroll', updateListPosition, true)
|
|
220
435
|
window.addEventListener('resize', updateListPosition)
|
|
436
|
+
|
|
437
|
+
// Use nextTick to ensure the DOM is fully rendered
|
|
438
|
+
nextTick(() => {
|
|
439
|
+
if (input.value && input.value.$el) {
|
|
440
|
+
// Find the input element
|
|
441
|
+
const inputElement = input.value.$el.querySelector('input')
|
|
442
|
+
if (inputElement) {
|
|
443
|
+
// Remove the aria-describedby attribute
|
|
444
|
+
inputElement.removeAttribute('aria-describedby')
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
})
|
|
221
448
|
})
|
|
222
449
|
|
|
223
450
|
onUnmounted(() => {
|
|
@@ -238,27 +465,45 @@
|
|
|
238
465
|
ref="input"
|
|
239
466
|
v-model="selectedItemText"
|
|
240
467
|
v-click-outside="closeList"
|
|
241
|
-
:title="labelWithAsterisk"
|
|
468
|
+
:title="$attrs['aria-label'] || labelWithAsterisk"
|
|
242
469
|
color="primary"
|
|
243
470
|
tabindex="0"
|
|
244
471
|
:disabled="disabled"
|
|
245
472
|
:label="labelWithAsterisk"
|
|
246
|
-
:aria-label="labelWithAsterisk"
|
|
473
|
+
:aria-label="$attrs['aria-label'] || labelWithAsterisk"
|
|
247
474
|
:error-messages="props.disableErrorHandling ? [] : errorMessages"
|
|
248
475
|
:variant="outlined ? 'outlined' : 'underlined'"
|
|
249
476
|
:rules="isRequired && !props.disableErrorHandling ? ['Le champ est requis.'] : []"
|
|
250
|
-
:display-asterisk="displayAsterisk"
|
|
251
477
|
:bg-color="props.bgColor"
|
|
252
478
|
:density="props.density"
|
|
479
|
+
:active="hasChips || isOpen"
|
|
253
480
|
readonly
|
|
254
481
|
:hide-details="props.hideMessages"
|
|
255
482
|
class="sy-select"
|
|
256
483
|
:width="calculatedWidth"
|
|
257
484
|
:style="hasError ? { minWidth: `${labelWidth + 18}px`} : {minWidth: `${labelWidth}px`}"
|
|
485
|
+
v-bind="Object.fromEntries(Object.entries($attrs).filter(([key]) => key !== 'display-asterisk'))"
|
|
258
486
|
@click="toggleMenu"
|
|
259
487
|
@keydown.enter.prevent="toggleMenu"
|
|
260
488
|
@keydown.space.prevent="toggleMenu"
|
|
261
489
|
>
|
|
490
|
+
<template
|
|
491
|
+
v-if="hasChips"
|
|
492
|
+
#default
|
|
493
|
+
>
|
|
494
|
+
<div class="d-flex flex-wrap gap-1">
|
|
495
|
+
<VChip
|
|
496
|
+
v-for="item in selectedItem"
|
|
497
|
+
:key="props.returnObject ? item[props.valueKey] : item"
|
|
498
|
+
size="small"
|
|
499
|
+
class="ma-1"
|
|
500
|
+
closable
|
|
501
|
+
@click:close="removeChip(item)"
|
|
502
|
+
>
|
|
503
|
+
{{ getChipText(item) }}
|
|
504
|
+
</VChip>
|
|
505
|
+
</div>
|
|
506
|
+
</template>
|
|
262
507
|
<template #append-inner>
|
|
263
508
|
<VIcon
|
|
264
509
|
v-if="hasError"
|
|
@@ -293,6 +538,7 @@
|
|
|
293
538
|
}"
|
|
294
539
|
bg-color="white"
|
|
295
540
|
@keydown.esc.prevent="isOpen = false"
|
|
541
|
+
@click.stop
|
|
296
542
|
>
|
|
297
543
|
<VListItem
|
|
298
544
|
v-for="(item, index) in formattedItems"
|
|
@@ -300,16 +546,24 @@
|
|
|
300
546
|
:ref="'options-' + index"
|
|
301
547
|
role="option"
|
|
302
548
|
class="v-list-item"
|
|
303
|
-
:aria-selected="
|
|
304
|
-
? selectedItem && selectedItem[props.valueKey] === item[props.valueKey]
|
|
305
|
-
: selectedItem === item[props.valueKey]"
|
|
549
|
+
:aria-selected="isItemSelected(item)"
|
|
306
550
|
:tabindex="index + 1"
|
|
307
|
-
:class="{ active:
|
|
308
|
-
|
|
309
|
-
: selectedItem === item[props.valueKey]
|
|
310
|
-
}"
|
|
311
|
-
@click="selectItem(item)"
|
|
551
|
+
:class="{ active: isItemSelected(item) }"
|
|
552
|
+
@click.stop="(event) => selectItem(item, event)"
|
|
312
553
|
>
|
|
554
|
+
<template
|
|
555
|
+
v-if="props.multiple && !isDefaultOption(item)"
|
|
556
|
+
#prepend
|
|
557
|
+
>
|
|
558
|
+
<VCheckbox
|
|
559
|
+
:model-value="isItemSelected(item)"
|
|
560
|
+
density="compact"
|
|
561
|
+
hide-details
|
|
562
|
+
color="primary"
|
|
563
|
+
class="mt-0 pt-0 mr-1"
|
|
564
|
+
@click.stop="(event) => selectItem(item, event)"
|
|
565
|
+
/>
|
|
566
|
+
</template>
|
|
313
567
|
<VListItemTitle>
|
|
314
568
|
{{ getItemText(item) }}
|
|
315
569
|
</VListItemTitle>
|
|
@@ -370,8 +624,13 @@
|
|
|
370
624
|
opacity: var(--v-medium-emphasis-opacity) !important;
|
|
371
625
|
}
|
|
372
626
|
|
|
627
|
+
.v-chip {
|
|
628
|
+
margin: 2px;
|
|
629
|
+
}
|
|
630
|
+
|
|
373
631
|
:deep(.v-field__input) {
|
|
374
632
|
color: tokens.$grey-darken-20;
|
|
633
|
+
cursor: pointer;
|
|
375
634
|
}
|
|
376
635
|
|
|
377
636
|
.hidden-label {
|