@cnamts/synapse 1.0.11 → 1.0.12

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.
Files changed (108) hide show
  1. package/dist/{DateFilter-QEfKOz0P.js → DateFilter-DoCcOfDW.js} +1 -1
  2. package/dist/{NumberFilter-C0h7gVzp.js → NumberFilter-9uR8uo6p.js} +1 -1
  3. package/dist/{PeriodFilter-8dVrKjju.js → PeriodFilter-CxN5ini7.js} +1 -1
  4. package/dist/{SelectFilter-BI3QGbqb.js → SelectFilter-bfxipgvt.js} +1 -1
  5. package/dist/{TextFilter-UOp1hcPp.js → TextFilter-yCnWcmW2.js} +1 -1
  6. package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordion.d.ts +6 -2
  7. package/dist/components/Amelipro/AmeliproAccordionList/AmeliproAccordionList.d.ts +2 -0
  8. package/dist/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.d.ts +6 -2
  9. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +6 -6
  10. package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +6 -6
  11. package/dist/components/Amelipro/AmeliproTable/AmeliproTable.d.ts +4 -0
  12. package/dist/components/Amelipro/AmeliproTable/types.d.ts +11 -0
  13. package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +6 -6
  14. package/dist/components/CookiesSelection/CookiesInformation/CookiesInformation.d.ts +14 -14
  15. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +3 -3
  16. package/dist/components/Customs/SyTextField/SyTextField.d.ts +1 -1
  17. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +40 -4
  18. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +46 -4
  19. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +5 -10
  20. package/dist/components/DatePicker/composables/useDatePickerViewMode.d.ts +2 -1
  21. package/dist/components/DatePicker/tests/setup.d.ts +368 -8
  22. package/dist/components/HeaderToolbar/HeaderToolbar.d.ts +6 -6
  23. package/dist/components/NirField/NirField.d.ts +4 -2
  24. package/dist/components/PeriodField/PeriodField.d.ts +80 -0
  25. package/dist/components/SearchListField/SearchListField.d.ts +3 -3
  26. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +5 -8
  27. package/dist/components/Tables/SyTable/SyTable.d.ts +5 -8
  28. package/dist/components/Tables/common/SyTablePagination.d.ts +3 -3
  29. package/dist/components/Tables/common/types.d.ts +4 -0
  30. package/dist/components/Tables/common/usePagination.d.ts +3 -4
  31. package/dist/components/Tables/common/useTableCheckbox.d.ts +10 -6
  32. package/dist/design-system-v3.js +1 -1
  33. package/dist/design-system-v3.umd.cjs +127 -127
  34. package/dist/{main-DyEOPqqn.js → main-DMXtXK3y.js} +9984 -9855
  35. package/dist/style.css +1 -1
  36. package/package.json +1 -1
  37. package/src/assets/overrides/_forms.scss +2 -0
  38. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.stories.ts +7 -4
  39. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.vue +2 -0
  40. package/src/components/Amelipro/AmeliproAccordionFrieze/AmeliproAccordionFrieze.vue +1 -0
  41. package/src/components/Amelipro/AmeliproAccordionFrieze/__tests__/__snapshots__/AmeliproAccordionFrieze.spec.ts.snap +574 -112
  42. package/src/components/Amelipro/AmeliproAccordionList/AmeliproAccordionList.stories.ts +5 -2
  43. package/src/components/Amelipro/AmeliproAccordionList/AmeliproAccordionList.vue +2 -1
  44. package/src/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.stories.ts +6 -3
  45. package/src/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.vue +2 -0
  46. package/src/components/Amelipro/AmeliproAccordionResultList/AmeliproAccordionResultList.stories.ts +5 -2
  47. package/src/components/Amelipro/AmeliproAccordionResultList/AmeliproAccordionResultList.vue +2 -1
  48. package/src/components/Amelipro/AmeliproCheckbox/__tests__/AmeliproCheckbox.spec.ts +175 -0
  49. package/src/components/Amelipro/AmeliproCheckbox/__tests__/__snapshots__/AmeliproCheckbox.spec.ts.snap +88 -0
  50. package/src/components/Amelipro/AmeliproCheckboxGroup/__tests__/AmeliproCheckboxGroup.spec.ts +423 -0
  51. package/src/components/Amelipro/AmeliproCheckboxGroup/{tests → __tests__}/__snapshots__/AmeliproCheckboxGroup.spec.ts.snap +112 -78
  52. package/src/components/Amelipro/AmeliproChips/__tests__/AmeliproChips.spec.ts +92 -0
  53. package/src/components/Amelipro/AmeliproChips/__tests__/__snapshots__/AmeliproChips.spec.ts.snap +81 -0
  54. package/src/components/Amelipro/AmeliproDialog/__tests__/AmeliproDialog.spec.ts +257 -0
  55. package/src/components/Amelipro/AmeliproDialog/__tests__/__snapshots__/AmeliproDialog.spec.ts.snap +61 -0
  56. package/src/components/Amelipro/AmeliproDisclosure/__tests__/AmeliproDisclosure.spec.ts +79 -0
  57. package/src/components/Amelipro/AmeliproDisclosure/__tests__/__snapshots__/AmeliproDisclosure.spec.ts.snap +89 -0
  58. package/src/components/Amelipro/AmeliproTable/AmeliproTable.stories.ts +81 -9
  59. package/src/components/Amelipro/AmeliproTable/AmeliproTable.vue +139 -61
  60. package/src/components/Amelipro/AmeliproTable/__tests__/AmeliproTable.spec.ts +10 -0
  61. package/src/components/Amelipro/AmeliproTable/__tests__/__snapshots__/AmeliproTable.spec.ts.snap +361 -187
  62. package/src/components/Amelipro/AmeliproTable/types.d.ts +11 -0
  63. package/src/components/Customs/SyTextField/SyTextField.vue +27 -5
  64. package/src/components/DatePicker/CalendarMode/DatePicker.vue +31 -8
  65. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +44 -12
  66. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +2 -2
  67. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +7 -1
  68. package/src/components/DatePicker/composables/tests/useDatePickerViewMode.spec.ts +107 -72
  69. package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +6 -6
  70. package/src/components/DatePicker/composables/useDatePickerViewMode.ts +57 -7
  71. package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +14 -14
  72. package/src/components/DatePicker/tests/navigation.regression.spec.ts +74 -0
  73. package/src/components/DatePicker/tests/navigation.simple.spec.ts +137 -0
  74. package/src/components/NirField/NirField.stories.ts +11 -2
  75. package/src/components/NirField/NirField.vue +21 -9
  76. package/src/components/RangeField/tests/RangeField.spec.ts +0 -3
  77. package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -0
  78. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +309 -0
  79. package/src/components/Tables/SyServerTable/SyServerTable.vue +18 -3
  80. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +67 -0
  81. package/src/components/Tables/SyTable/SyTable.mdx +15 -0
  82. package/src/components/Tables/SyTable/SyTable.stories.ts +228 -0
  83. package/src/components/Tables/SyTable/SyTable.vue +18 -3
  84. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +63 -0
  85. package/src/components/Tables/common/SyTablePagination.vue +10 -8
  86. package/src/components/Tables/common/types.ts +4 -0
  87. package/src/components/Tables/common/usePagination.ts +11 -20
  88. package/src/components/Tables/common/useTableCheckbox.ts +23 -11
  89. package/src/composables/validation/AvecVosComposants.mdx.old +1 -1
  90. package/src/composables/validation/FormValidation.stories.ts.old +5 -5
  91. package/src/stories/Accessibilite/Introduction.mdx +1 -1
  92. package/src/stories/Demarrer/EnrichirLeDesignSystem.mdx +43 -0
  93. package/src/stories/Demarrer/EnrichirLeDesignSystem.stories.ts +239 -0
  94. package/src/stories/Demarrer/SignalerUneAnomalie.mdx +39 -0
  95. package/src/stories/Demarrer/SignalerUneAnomalie.stories.ts +261 -0
  96. package/src/components/Amelipro/AmeliproCheckbox/tests/AmeliproCheckbox.spec.ts +0 -19
  97. package/src/components/Amelipro/AmeliproCheckbox/tests/__snapshots__/AmeliproCheckbox.spec.ts.snap +0 -40
  98. package/src/components/Amelipro/AmeliproCheckboxGroup/tests/AmeliproCheckboxGroup.spec.ts +0 -46
  99. package/src/components/Amelipro/AmeliproChips/tests/AmeliproChips.spec.ts +0 -16
  100. package/src/components/Amelipro/AmeliproChips/tests/__snapshots__/AmeliproChips.spec.ts.snap +0 -97
  101. package/src/components/Amelipro/AmeliproDialog/tests/AmeliproDialog.spec.ts +0 -24
  102. package/src/components/Amelipro/AmeliproDialog/tests/__snapshots__/AmeliproDialog.spec.ts.snap +0 -134
  103. package/src/components/Amelipro/AmeliproDisclosure/tests/AmeliproDisclosure.spec.ts +0 -19
  104. package/src/components/Amelipro/AmeliproDisclosure/tests/__snapshots__/AmeliproDisclosure.spec.ts.snap +0 -104
  105. package/src/components/BackBtn/tests/__snapshots__/BackBtn.spec.ts.snap +0 -45
  106. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +0 -1270
  107. package/src/stories/Demarrer/CreerUneIssue.mdx +0 -67
  108. package/src/stories/Demarrer/components.stories.ts +0 -25
@@ -5,6 +5,7 @@ import SyTable from './SyTable.vue'
5
5
  import type { DataOptions, FilterType } from '../common/types'
6
6
  import type { VDataTable } from 'vuetify/components'
7
7
  import dayjs from 'dayjs'
8
+ import { mdiChevronDown, mdiChevronUp } from '@mdi/js'
8
9
 
9
10
  const meta = {
10
11
  title: 'Composants/Tableaux/SyTable',
@@ -83,6 +84,13 @@ const meta = {
83
84
  },
84
85
  required: true,
85
86
  },
87
+ showExpand: {
88
+ description: 'Affiche une colonne permettant d\'étendre les lignes pour afficher du contenu supplémentaire',
89
+ control: { type: 'boolean' },
90
+ table: {
91
+ category: 'props',
92
+ },
93
+ },
86
94
  resizableColumns: {
87
95
  description: 'Permet de redimensionner les colonnes du tableau',
88
96
  control: { type: 'boolean' },
@@ -140,6 +148,15 @@ const meta = {
140
148
  type: { summary: 'boolean' },
141
149
  },
142
150
  },
151
+ selectionKey: {
152
+ description: 'Clé utilisée pour identifier chaque ligne lors de la sélection. Par défaut, utilise "id" si présent, sinon l\'objet complet.',
153
+ control: { type: 'text' },
154
+ table: {
155
+ category: 'props',
156
+ type: { summary: 'string' },
157
+ defaultValue: { summary: 'undefined (fallback: id | objet complet)' },
158
+ },
159
+ },
143
160
  },
144
161
  } satisfies Meta<typeof SyTable & typeof VDataTable>
145
162
 
@@ -3013,6 +3030,217 @@ export const ColumnControls: Story = {
3013
3030
  },
3014
3031
  }
3015
3032
 
3033
+ export const ExpandableRows: Story = {
3034
+ parameters: {
3035
+ sourceCode: [
3036
+ {
3037
+ name: 'Template',
3038
+ code: `
3039
+ <template>
3040
+ <SyTable
3041
+ v-model:options="options"
3042
+ :headers="headers"
3043
+ :items="items"
3044
+ show-expand
3045
+ caption="Tableau complexe"
3046
+ suffix="expand-table"
3047
+ >
3048
+ <template #item.data-table-expand="{ internalItem, isExpanded, toggleExpand }">
3049
+ <v-btn
3050
+ :append-icon="isExpanded(internalItem) ? mdiChevronUp : mdiChevronDown"
3051
+ :text="isExpanded(internalItem) ? 'Fermer' : \`Plus d'info\`"
3052
+ class="text-none"
3053
+ color="medium-emphasis"
3054
+ size="small"
3055
+ variant="text"
3056
+ width="105"
3057
+ border
3058
+ slim
3059
+ @click="toggleExpand(internalItem)"
3060
+ />
3061
+ </template>
3062
+
3063
+ <template #expanded-row="{ columns, item }">
3064
+ <tr>
3065
+ <td
3066
+ :colspan="columns.length"
3067
+ class="py-2"
3068
+ >
3069
+ <strong>Informations complémentaires :</strong>
3070
+ <p>Plus de détails pour {{ item.firstname }} {{ item.lastname }}.</p>
3071
+ </td>
3072
+ </tr>
3073
+ </template>
3074
+ </SyTable>
3075
+ `,
3076
+ },
3077
+ {
3078
+ name: 'Script',
3079
+ code: `
3080
+ <script setup lang="ts">
3081
+ import { ref } from 'vue'
3082
+ import { SyTable } from '@cnamts/synapse'
3083
+ import { mdiChevronDown, mdiChevronUp } from '@mdi/js'
3084
+
3085
+ const options = ref({
3086
+ itemsPerPage: 4,
3087
+ })
3088
+
3089
+ const headers = ref([
3090
+ {
3091
+ title: 'Nom',
3092
+ key: 'lastname',
3093
+ },
3094
+ {
3095
+ title: 'Prénom',
3096
+ key: 'firstname',
3097
+ },
3098
+ {
3099
+ title: 'Email',
3100
+ value: 'email',
3101
+ },
3102
+ ])
3103
+
3104
+ const items = ref([
3105
+ {
3106
+ firstname: 'Virginie',
3107
+ lastname: 'Beauchesne',
3108
+ email: 'virginie.beauchesne@example.com',
3109
+ },
3110
+ {
3111
+ firstname: 'Simone',
3112
+ lastname: 'Bellefeuille',
3113
+ email: 'simone.bellefeuille@example.com',
3114
+ },
3115
+ {
3116
+ firstname: 'Étienne',
3117
+ lastname: 'Salois',
3118
+ email: 'etienne.salois@example.com',
3119
+ },
3120
+ {
3121
+ firstname: 'Thierry',
3122
+ lastname: 'Bobu',
3123
+ email: 'thierry.bobu@example.com',
3124
+ },
3125
+ {
3126
+ firstname: 'Bernadette',
3127
+ lastname: 'Langelier',
3128
+ email: 'bernadette.langelier@exemple.com'
3129
+ },
3130
+ {
3131
+ firstname: 'Agate',
3132
+ lastname: 'Roy',
3133
+ email: 'agate.roy@exemple.com'
3134
+ }
3135
+ ])
3136
+ </script>
3137
+ `,
3138
+ },
3139
+ ],
3140
+ },
3141
+ args: {
3142
+ 'headers': [
3143
+ {
3144
+ title: 'Nom',
3145
+ key: 'lastname',
3146
+ },
3147
+ {
3148
+ title: 'Prénom',
3149
+ key: 'firstname',
3150
+ },
3151
+ {
3152
+ title: 'Email',
3153
+ value: 'email',
3154
+ },
3155
+ ],
3156
+ 'items': [
3157
+ {
3158
+ firstname: 'Virginie',
3159
+ lastname: 'Beauchesne',
3160
+ email: 'virginie.beauchesne@example.com',
3161
+ },
3162
+ {
3163
+ firstname: 'Simone',
3164
+ lastname: 'Bellefeuille',
3165
+ email: 'simone.bellefeuille@example.com',
3166
+ },
3167
+ {
3168
+ firstname: 'Étienne',
3169
+ lastname: 'Salois',
3170
+ email: 'etienne.salois@example.com',
3171
+ },
3172
+ {
3173
+ firstname: 'Thierry',
3174
+ lastname: 'Bobu',
3175
+ email: 'thierry.bobu@example.com',
3176
+ },
3177
+ {
3178
+ firstname: 'Bernadette',
3179
+ lastname: 'Langelier',
3180
+ email: 'bernadette.langelier@exemple.com',
3181
+ },
3182
+ {
3183
+ firstname: 'Agate',
3184
+ lastname: 'Roy',
3185
+ email: 'agate.roy@exemple.com',
3186
+ },
3187
+ ],
3188
+ 'options': {
3189
+ itemsPerPage: 4,
3190
+ },
3191
+ 'caption': '',
3192
+ 'showExpand': true,
3193
+ 'suffix': 'expandable-table',
3194
+ 'density': 'default',
3195
+ 'striped': false,
3196
+ 'onUpdate:options': fn(),
3197
+ },
3198
+ render: (args) => {
3199
+ return {
3200
+ components: { SyTable },
3201
+ setup() {
3202
+ return { args, mdiChevronDown, mdiChevronUp }
3203
+ },
3204
+ template: `
3205
+ <SyTable
3206
+ v-model:options="args.options"
3207
+ v-bind="args"
3208
+ show-expand
3209
+ caption="Tableau complexe"
3210
+ suffix="expand-table"
3211
+ >
3212
+ <template #item.data-table-expand="{ internalItem, isExpanded, toggleExpand }">
3213
+ <v-btn
3214
+ :append-icon="isExpanded(internalItem) ? mdiChevronUp : mdiChevronDown"
3215
+ :text="isExpanded(internalItem) ? 'Fermer' : \`Plus d'info\`"
3216
+ class="text-none"
3217
+ color="medium-emphasis"
3218
+ size="small"
3219
+ variant="text"
3220
+ width="105"
3221
+ border
3222
+ slim
3223
+ @click="toggleExpand(internalItem)"
3224
+ />
3225
+ </template>
3226
+
3227
+ <template #expanded-row="{ columns, item }">
3228
+ <tr>
3229
+ <td
3230
+ :colspan="columns.length"
3231
+ class="py-2"
3232
+ >
3233
+ <strong>Informations complémentaires :</strong>
3234
+ <p>Plus de détails pour {{ item.firstname }} {{ item.lastname }}.</p>
3235
+ </td>
3236
+ </tr>
3237
+ </template>
3238
+ </SyTable>
3239
+ `,
3240
+ }
3241
+ },
3242
+ }
3243
+
3016
3244
  export const SlotItem: Story = {
3017
3245
  parameters: {
3018
3246
  sourceCode: [
@@ -99,12 +99,25 @@
99
99
 
100
100
  // Use the pagination composable
101
101
  const itemsLength = computed(() => filteredItems.value.length)
102
- const { page, pageCount, itemsPerPageValue, updateItemsPerPage } = usePagination({
102
+ const { page, pageCount, itemsPerPageValue, updateItemsPerPage, isUpdatingItemsPerPage } = usePagination({
103
103
  options,
104
104
  itemsLength,
105
- table,
106
105
  })
107
106
 
107
+ // Defines a function to handle updating the data table options
108
+ function onUpdateOptions(newOptions: Partial<DataOptions>) {
109
+ if (isUpdatingItemsPerPage.value && typeof newOptions.itemsPerPage !== 'undefined') {
110
+ // Creates a copy of the received options
111
+ const rest = { ...newOptions }
112
+ delete (rest as Record<string, unknown>).itemsPerPage
113
+ // Updates the other options without modifying itemsPerPage
114
+ updateOptions(rest)
115
+ return
116
+ }
117
+ // In all other cases, simply updates the options with the new values
118
+ updateOptions(newOptions)
119
+ }
120
+
108
121
  // Use the table checkbox composable
109
122
  const { toggleAllRows, getItemValue } = useTableCheckbox({
110
123
  items: filteredItems,
@@ -112,6 +125,7 @@
112
125
  updateModelValue: (value) => {
113
126
  model.value = value
114
127
  },
128
+ selectionKey: toRef(props, 'selectionKey'),
115
129
  })
116
130
 
117
131
  // Use the ARIA accessibility composable
@@ -231,7 +245,8 @@
231
245
  :item-value="getItemValue"
232
246
  :multi-sort="props.multiSort"
233
247
  :must-sort="props.mustSort"
234
- @update:options="updateOptions"
248
+ :show-expand="props.showExpand"
249
+ @update:options="onUpdateOptions"
235
250
  >
236
251
  <template #top>
237
252
  <caption
@@ -658,3 +658,66 @@ describe('SyTable', () => {
658
658
  wrapper.unmount()
659
659
  })
660
660
  })
661
+
662
+ describe('SyTable selectionKey', () => {
663
+ it('uses custom selectionKey when provided', () => {
664
+ const items = [
665
+ { id: 1, uuid: 'a-1', name: 'A' },
666
+ { id: 2, uuid: 'a-2', name: 'B' },
667
+ ]
668
+ const wrapper = mount(SyTable, {
669
+ props: {
670
+ headers,
671
+ items,
672
+ showSelect: true,
673
+ selectionKey: 'uuid',
674
+ suffix: '',
675
+ },
676
+ })
677
+
678
+ const dataTable = wrapper.findComponent({ name: 'VDataTable' })
679
+ const itemValue = dataTable.props('itemValue') as (item: unknown) => unknown
680
+
681
+ expect(itemValue(items[0] as unknown as Record<string, unknown>)).toBe('a-1')
682
+ expect(itemValue(items[1] as unknown as Record<string, unknown>)).toBe('a-2')
683
+ })
684
+
685
+ it('falls back to id when selectionKey is missing on item', () => {
686
+ const items = [
687
+ { id: 10, name: 'No UUID' },
688
+ ]
689
+ const wrapper = mount(SyTable, {
690
+ props: {
691
+ headers,
692
+ items,
693
+ showSelect: true,
694
+ selectionKey: 'uuid',
695
+ suffix: '',
696
+ },
697
+ })
698
+
699
+ const dataTable = wrapper.findComponent({ name: 'VDataTable' })
700
+ const itemValue = dataTable.props('itemValue') as (item: unknown) => unknown
701
+
702
+ expect(itemValue(items[0] as unknown as Record<string, unknown>)).toBe(10)
703
+ })
704
+
705
+ it('falls back to full object when neither selectionKey nor id are present', () => {
706
+ const item = { name: 'No keys' }
707
+ const wrapper = mount(SyTable, {
708
+ props: {
709
+ headers,
710
+ items: [item],
711
+ showSelect: true,
712
+ selectionKey: 'uuid',
713
+ suffix: '',
714
+ },
715
+ })
716
+
717
+ const dataTable = wrapper.findComponent({ name: 'VDataTable' })
718
+ const itemValue = dataTable.props('itemValue') as (item: unknown) => unknown
719
+
720
+ const result = itemValue(item as unknown as Record<string, unknown>)
721
+ expect(result).toBe(item) // same object reference
722
+ })
723
+ })
@@ -67,6 +67,15 @@
67
67
  emit('update:page', pageNumber)
68
68
  }
69
69
 
70
+ /**
71
+ * Handle change from the SySelect component directly
72
+ * Ensure we emit a number for items-per-page, then reset to page 1
73
+ */
74
+ function handleItemsPerPageChange(value: unknown) {
75
+ const numeric = typeof value === 'string' ? Number.parseInt(value, 10) : (value as number)
76
+ emit('update:items-per-page', numeric)
77
+ }
78
+
70
79
  /**
71
80
  * Local items per page with two-way binding
72
81
  */
@@ -78,14 +87,6 @@
78
87
  localItemsPerPage.value = newValue
79
88
  })
80
89
 
81
- // Watch for local changes and emit events
82
- watch(localItemsPerPage, (newValue) => {
83
- // First reset to page 1 when changing items per page
84
- emit('update:page', 1)
85
- // Then update the items per page
86
- emit('update:items-per-page', newValue)
87
- })
88
-
89
90
  // Remove aria-describedby attribute after component is mounted
90
91
  onMounted(() => {
91
92
  // Use nextTick to ensure the DOM is fully rendered
@@ -149,6 +150,7 @@
149
150
  :label="''"
150
151
  style="width: 90px;"
151
152
  :clearable="false"
153
+ @update:model-value="handleItemsPerPageChange"
152
154
  />
153
155
  </div>
154
156
  </div>
@@ -90,6 +90,8 @@ export type SyTableProps = {
90
90
  enableColumnControls?: boolean
91
91
  headers?: DataTableHeaders[]
92
92
  showSelect?: boolean
93
+ showExpand?: boolean
94
+ selectionKey?: string
93
95
  multiSort?: boolean
94
96
  mustSort?: boolean
95
97
  itemsPerPageOptions?: number[]
@@ -109,6 +111,8 @@ export type SyServerTableProps = {
109
111
  enableColumnControls?: boolean
110
112
  headers?: DataTableHeaders[]
111
113
  showSelect?: boolean
114
+ showExpand?: boolean
115
+ selectionKey?: string
112
116
  multiSort?: boolean
113
117
  mustSort?: boolean
114
118
  itemsPerPageOptions?: number[]
@@ -1,4 +1,4 @@
1
- import { computed, nextTick, type Ref } from 'vue'
1
+ import { computed, nextTick, ref, type Ref } from 'vue'
2
2
  import type { DataOptions } from './types'
3
3
 
4
4
  /**
@@ -6,18 +6,17 @@ import type { DataOptions } from './types'
6
6
  *
7
7
  * @param options - Reactive reference to table options
8
8
  * @param itemsLength - Total number of items (for client-side) or serverItemsLength (for server-side)
9
- * @param table - Reference to the table component
10
9
  * @returns Pagination utilities and computed properties
11
10
  */
12
11
  export function usePagination({
13
12
  options,
14
13
  itemsLength,
15
- table,
16
14
  }: {
17
15
  options: Ref<Partial<DataOptions>>
18
16
  itemsLength: Ref<number>
19
- table: Ref<unknown>
20
17
  }) {
18
+ // Flag to indicate an ongoing items-per-page update cycle
19
+ const isUpdatingItemsPerPage = ref(false)
21
20
  // Current page with getter/setter
22
21
  const page = computed({
23
22
  get: () => options.value.page || 1,
@@ -47,25 +46,16 @@ export function usePagination({
47
46
  /**
48
47
  * Update items per page from pagination component
49
48
  */
50
- function updateItemsPerPage(newItemsPerPage: number) {
51
- // Create a completely new options object to force reactivity
52
- const newOptions = {
49
+ async function updateItemsPerPage(newItemsPerPage: number) {
50
+ isUpdatingItemsPerPage.value = true
51
+ await nextTick()
52
+ options.value = {
53
53
  ...options.value,
54
54
  itemsPerPage: newItemsPerPage,
55
- page: 1, // Reset to first page when changing items per page
55
+ page: 1,
56
56
  }
57
-
58
- // Update options with the new object
59
- options.value = newOptions
60
-
61
- // Force a refresh of the table
62
- nextTick(() => {
63
- // Try to force update if the table has that method
64
- const tableValue = table.value as { $forceUpdate?: () => void }
65
- if (tableValue && typeof tableValue.$forceUpdate === 'function') {
66
- tableValue.$forceUpdate()
67
- }
68
- })
57
+ await nextTick()
58
+ isUpdatingItemsPerPage.value = false
69
59
  }
70
60
 
71
61
  return {
@@ -73,5 +63,6 @@ export function usePagination({
73
63
  pageCount,
74
64
  itemsPerPageValue,
75
65
  updateItemsPerPage,
66
+ isUpdatingItemsPerPage,
76
67
  }
77
68
  }
@@ -3,29 +3,41 @@ import { toRef } from 'vue'
3
3
 
4
4
  interface UseTableCheckboxOptions {
5
5
  /**
6
- * The items to be displayed in the table
7
- */
6
+ * The items to be displayed in the table
7
+ */
8
8
  items: MaybeRefOrGetter<Record<string, unknown>[]>
9
9
  /**
10
- * The model value for selected items
11
- */
10
+ * The model value for selected items
11
+ */
12
12
  modelValue: MaybeRefOrGetter<unknown[]>
13
13
  /**
14
- * Function to update the model value
15
- */
14
+ * Function to update the model value
15
+ */
16
16
  updateModelValue: (value: unknown[]) => void
17
+ /**
18
+ * Optional key to use for item selection value. If not provided, falls back to `id` then the full object.
19
+ */
20
+ selectionKey?: MaybeRefOrGetter<string | undefined>
17
21
  }
18
22
  export function useTableCheckbox(options: UseTableCheckboxOptions) {
19
23
  const itemsRef = toRef(options.items)
20
24
  const modelValueRef = toRef(options.modelValue)
25
+ const selectionKeyRef = toRef(options as { selectionKey?: MaybeRefOrGetter<string | undefined> }, 'selectionKey')
21
26
 
22
27
  /**
23
- * Function to get a unique identifier for each item
24
- */
28
+ * Function to get a unique identifier for each item
29
+ */
25
30
  const getItemValue = (item: Record<string, unknown>) => {
26
- // If the item has an id field, use that
27
- if ((item as Record<string, unknown>).id !== undefined) {
28
- return (item as Record<string, unknown>).id
31
+ // 1) If a custom selectionKey is provided and exists on item, use it
32
+ const key = (typeof selectionKeyRef?.value === 'function'
33
+ ? (selectionKeyRef.value as unknown as () => string | undefined)()
34
+ : selectionKeyRef?.value) as string | undefined
35
+ if (key && typeof key === 'string' && item[key] !== undefined) {
36
+ return item[key]
37
+ }
38
+ // 2) Otherwise, if the item has an id field, use that
39
+ if (item.id !== undefined) {
40
+ return item.id
29
41
  }
30
42
  // Otherwise, return the full object instead of a JSON string
31
43
  // so v-model contains real objects
@@ -1,6 +1,6 @@
1
1
  import { Meta, Source } from '@storybook/blocks';
2
2
 
3
- <Meta title="Composables/ValidationSystem/Avec Vos Composants" />
3
+ <Meta title="Guide Du Dev/SyForm/Avec Vos Composants" />
4
4
 
5
5
  <div className="header">
6
6
  <h1>Etendre le système à vos propres composants</h1>
@@ -11,7 +11,7 @@ import { VBtn, VTextField } from 'vuetify/components'
11
11
  * La documentation sur le système de validation en cascade de Synapse Design System.
12
12
  */
13
13
  export default {
14
- title: 'Composables/ValidationSystem',
14
+ title: 'Guide Du Dev/SyForm',
15
15
  component: SyForm,
16
16
  argTypes: {
17
17
  validateOnSubmit: {
@@ -32,7 +32,7 @@ export default {
32
32
  type Story = StoryObj<typeof SyForm>
33
33
 
34
34
  // Exemple de base
35
- export const SimpleForm: Story = {
35
+ export const FormulaireSimple: Story = {
36
36
  render: args => ({
37
37
  components: { SyForm, SyTextField, VBtn },
38
38
  setup() {
@@ -100,7 +100,7 @@ const onSubmit = (event: { isValid: boolean }) => {
100
100
  }
101
101
 
102
102
  // Exemple de formulaire avec composants mixtes
103
- export const MixedComponentsForm: Story = {
103
+ export const FormulaireMixte: Story = {
104
104
  render: args => ({
105
105
  components: { SyForm, SyTextField, SySelect, SyCheckbox, DatePicker, VBtn, VTextField },
106
106
  setup() {
@@ -216,7 +216,7 @@ const onSubmit = (event: { isValid: boolean }) => {
216
216
  }
217
217
 
218
218
  // Exemple de formulaire imbriqué
219
- export const NestedForm: Story = {
219
+ export const FormulaireImbrique: Story = {
220
220
  render: args => ({
221
221
  components: { SyForm, SyTextField, VBtn },
222
222
  setup() {
@@ -313,7 +313,7 @@ const onSubmit = (event: { isValid: boolean }) => {
313
313
  }
314
314
 
315
315
  // Exemple d'implémentation personnalisée
316
- export const CustomImplementation: Story = {
316
+ export const ImplementationPersonnalisee: Story = {
317
317
  render: args => ({
318
318
  components: { SyForm, SyTextField, VBtn },
319
319
  setup() {
@@ -220,7 +220,7 @@ Pour répondre aux objectifs de mise en conformité des interfaces utilisateurs
220
220
  <div>
221
221
  <h3>Besoin d'accompagnement ?</h3>
222
222
  <p>Si vous avez besoin d'un accompagnement sur le sujet, merci de prendre contact avec <a href="mailto:valentin.becquet@assurance-maladie.fr">valentin.becquet@assurance-maladie.fr</a>.</p>
223
- <p>Pour toute remontée de problème liée à l'accessibilité, veuillez <a href="https://github.com/assurance-maladie-digital/design-system-v3/issues/new?template=accessibility.md">signaler un problème d'accessibilité</a>.</p>
223
+ <p>Pour toute remontée de problème liée à l'accessibilité, veuillez <a href="/?path=/docs/démarrer-signaler-une-anomalie--docs">signaler un problème d'accessibilité</a>.</p>
224
224
  </div>
225
225
  </div>
226
226
 
@@ -0,0 +1,43 @@
1
+ import {Meta, Story} from '@storybook/addon-docs/blocks';
2
+ import * as ComponentStories from './EnrichirLeDesignSystem.stories.ts';
3
+ import '../styles/shared.css';
4
+
5
+ <Meta title="Démarrer/Enrichir le Design System"/>
6
+
7
+ <div className="header">
8
+ <h1>Enrichir le Design System</h1>
9
+ </div>
10
+
11
+ ## Introduction
12
+
13
+ Le Design System de l'Assurance Maladie est un projet vivant qui évolue constamment pour répondre aux besoins des utilisateurs et aux avancées technologiques.<br/>
14
+ Votre contribution est essentielle pour garantir que le Design System reste pertinent, accessible et efficace.<br/>
15
+ Toute demande ne sera pas nécessairement intégrée, mais chaque suggestion est examinée avec attention par l'équipe du Studio Design.
16
+
17
+ <Story of={ComponentStories.InfoIntro}/>
18
+
19
+ <a id="exigences" />
20
+ ## Exigences requises pour acceptation d'un nouveau composant ou d'une nouvelle fonctionnalité
21
+
22
+ 1. Être **conforme aux exigences de la charte graphique** de la CNAM (tokens associés).
23
+ 2. Avoir un **intérêt d'usage pour plusieurs produits** de l'Assurance Maladie (une justification métier peut être demandée).
24
+ 3. Avoir un **intérêt d'usage ou de pertinence** par rapport aux **composants de la bibliothèque Vuetify**.
25
+ 4. Avoir un **intérêt d'usage ou de pertinence** par rapport aux **composants existant du Design System**.
26
+ 5. Doit permettre la **responsivité**.
27
+ 6. Doit permettre le **respect du Référentiel général d'amélioration de l'accessibilité** (RGAA).
28
+ 7. Doit permettre aux produits utilisateurs du composant de respecter des **bonnes pratiques d’éco-conception**.
29
+ 8. Doit permettre la **maintenabilité du composant**.
30
+ 9. Ne doit pas engendrer de **conflit** ou **régression** avec l'existant.
31
+ 10. Doit se conformer aux **exigences techniques** du Design System et à son bon fonctionnement sur le Starter Kit (VueJS 3, version des plugins...).
32
+
33
+ ## Créer une nouvelle demande
34
+
35
+ <Story of={ComponentStories.Optimisation}/>
36
+
37
+ <Story of={ComponentStories.AjoutFonctionnalite}/>
38
+
39
+ <Story of={ComponentStories.DeclinaisonFonctionnalite}/>
40
+
41
+ <Story of={ComponentStories.CreationComposant}/>
42
+
43
+ <Story of={ComponentStories.IntegrationComposant}/>