@cnamts/synapse 1.0.11 → 1.0.13

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 (200) hide show
  1. package/dist/{DateFilter-QEfKOz0P.js → DateFilter-_EFzsvvM.js} +1 -1
  2. package/dist/{NumberFilter-C0h7gVzp.js → NumberFilter-CUxEbKJh.js} +1 -1
  3. package/dist/{PeriodFilter-8dVrKjju.js → PeriodFilter-D5ueqtKy.js} +1 -1
  4. package/dist/{SelectFilter-BI3QGbqb.js → SelectFilter-BciBNydy.js} +1 -1
  5. package/dist/{TextFilter-UOp1hcPp.js → TextFilter-DMN_WAQB.js} +1 -1
  6. package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordion.d.ts +7 -3
  7. package/dist/components/Amelipro/AmeliproAccordion/AmeliproAccordionTemplate/AmeliproAccordionTemplate.d.ts +1 -1
  8. package/dist/components/Amelipro/AmeliproAccordionList/AmeliproAccordionList.d.ts +2 -0
  9. package/dist/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.d.ts +7 -3
  10. package/dist/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResultTemplate/AmeliproAccordionResultTemplate.d.ts +1 -1
  11. package/dist/components/Amelipro/AmeliproAutoCompleteField/AmeliproAutoCompleteField.d.ts +50 -68
  12. package/dist/components/Amelipro/AmeliproCard/AmeliproCard.d.ts +1 -1
  13. package/dist/components/Amelipro/AmeliproIcon/AmeliproIcon.d.ts +1 -1
  14. package/dist/components/Amelipro/AmeliproIconBtn/AmeliproIconBtn.d.ts +5 -5
  15. package/dist/components/Amelipro/AmeliproMultipleFoldingCard/AmeliproMultipleFoldingCard.d.ts +1 -1
  16. package/dist/components/Amelipro/AmeliproNumberedCard/AmeliproNumberedCard.d.ts +1 -1
  17. package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressCityRow/AmeliproPostalAddressCityRow.d.ts +24 -32
  18. package/dist/components/Amelipro/AmeliproPostalAddressField/AmeliproPostalAddressField.d.ts +36 -48
  19. package/dist/components/Amelipro/AmeliproSelect/AmeliproSelect.d.ts +50 -68
  20. package/dist/components/Amelipro/AmeliproTable/AmeliproTable.d.ts +4 -0
  21. package/dist/components/Amelipro/AmeliproTable/types.d.ts +11 -0
  22. package/dist/components/Amelipro/AmeliproTabs/AmeliproTabs.d.ts +50 -68
  23. package/dist/components/Amelipro/AmeliproTextArea/AmeliproTextArea.d.ts +0 -4
  24. package/dist/components/Amelipro/AmeliproTextField/AmeliproTextField.d.ts +12 -16
  25. package/dist/components/Captcha/Captcha.d.ts +68 -0
  26. package/dist/components/Captcha/CaptchaAlert.d.ts +13 -0
  27. package/dist/components/Captcha/CaptchaBase.d.ts +55 -0
  28. package/dist/components/Captcha/CaptchaBtn.d.ts +12 -0
  29. package/dist/components/Captcha/CaptchaForm.d.ts +16 -0
  30. package/dist/components/Captcha/CaptchaImg.d.ts +12 -0
  31. package/dist/components/Captcha/CaptchaInformation.d.ts +20 -0
  32. package/dist/components/Captcha/captchaApi.d.ts +41 -0
  33. package/dist/components/Captcha/icons/volumeUp.d.ts +2 -0
  34. package/dist/components/Captcha/locales.d.ts +35 -0
  35. package/dist/components/Captcha/types.d.ts +2 -0
  36. package/dist/components/ChipList/ChipList.d.ts +2 -2
  37. package/dist/components/CookiesSelection/CookiesInformation/CookiesInformation.d.ts +14 -14
  38. package/dist/components/Customs/Selects/SySelect/SySelect.d.ts +5 -5
  39. package/dist/components/Customs/SyForm/SyForm.d.ts +6 -3
  40. package/dist/components/Customs/SyTextField/SyTextField.d.ts +12 -16
  41. package/dist/components/DatePicker/CalendarMode/DatePicker.d.ts +96 -68
  42. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +63 -38
  43. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +23 -27
  44. package/dist/components/DatePicker/composables/useDatePickerViewMode.d.ts +2 -1
  45. package/dist/components/DatePicker/tests/setup.d.ts +816 -520
  46. package/dist/components/HeaderToolbar/HeaderToolbar.d.ts +10 -10
  47. package/dist/components/NirField/NirField.d.ts +31 -34
  48. package/dist/components/NirField/locales.d.ts +1 -3
  49. package/dist/components/PasswordField/PasswordField.d.ts +2 -0
  50. package/dist/components/PeriodField/PeriodField.d.ts +192 -128
  51. package/dist/components/PhoneField/PhoneField.d.ts +13 -17
  52. package/dist/components/SearchListField/SearchListField.d.ts +5 -5
  53. package/dist/components/SyTextArea/SyTextArea.d.ts +0 -4
  54. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +5 -8
  55. package/dist/components/Tables/SyTable/SyTable.d.ts +5 -8
  56. package/dist/components/Tables/common/SyTablePagination.d.ts +5 -5
  57. package/dist/components/Tables/common/types.d.ts +4 -0
  58. package/dist/components/Tables/common/usePagination.d.ts +3 -4
  59. package/dist/components/Tables/common/useTableCheckbox.d.ts +10 -6
  60. package/dist/components/index.d.ts +1 -0
  61. package/dist/composables/validation/useFormValidation.d.ts +10 -0
  62. package/dist/composables/validation/useValidatable.d.ts +10 -2
  63. package/dist/design-system-v3.js +126 -125
  64. package/dist/design-system-v3.umd.cjs +265 -265
  65. package/dist/main-DISHlqcd.js +34217 -0
  66. package/dist/style.css +1 -1
  67. package/package.json +1 -1
  68. package/src/assets/overrides/_forms.scss +2 -0
  69. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.stories.ts +7 -4
  70. package/src/components/Amelipro/AmeliproAccordion/AmeliproAccordion.vue +2 -0
  71. package/src/components/Amelipro/AmeliproAccordionFrieze/AmeliproAccordionFrieze.vue +1 -0
  72. package/src/components/Amelipro/AmeliproAccordionFrieze/__tests__/__snapshots__/AmeliproAccordionFrieze.spec.ts.snap +574 -112
  73. package/src/components/Amelipro/AmeliproAccordionList/AmeliproAccordionList.stories.ts +5 -2
  74. package/src/components/Amelipro/AmeliproAccordionList/AmeliproAccordionList.vue +2 -1
  75. package/src/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.stories.ts +6 -3
  76. package/src/components/Amelipro/AmeliproAccordionResult/AmeliproAccordionResult.vue +2 -0
  77. package/src/components/Amelipro/AmeliproAccordionResultList/AmeliproAccordionResultList.stories.ts +5 -2
  78. package/src/components/Amelipro/AmeliproAccordionResultList/AmeliproAccordionResultList.vue +2 -1
  79. package/src/components/Amelipro/AmeliproCheckbox/__tests__/AmeliproCheckbox.spec.ts +175 -0
  80. package/src/components/Amelipro/AmeliproCheckbox/__tests__/__snapshots__/AmeliproCheckbox.spec.ts.snap +88 -0
  81. package/src/components/Amelipro/AmeliproCheckboxGroup/__tests__/AmeliproCheckboxGroup.spec.ts +423 -0
  82. package/src/components/Amelipro/AmeliproCheckboxGroup/{tests → __tests__}/__snapshots__/AmeliproCheckboxGroup.spec.ts.snap +112 -78
  83. package/src/components/Amelipro/AmeliproChips/__tests__/AmeliproChips.spec.ts +92 -0
  84. package/src/components/Amelipro/AmeliproChips/__tests__/__snapshots__/AmeliproChips.spec.ts.snap +81 -0
  85. package/src/components/Amelipro/AmeliproDialog/__tests__/AmeliproDialog.spec.ts +257 -0
  86. package/src/components/Amelipro/AmeliproDialog/__tests__/__snapshots__/AmeliproDialog.spec.ts.snap +61 -0
  87. package/src/components/Amelipro/AmeliproDisclosure/__tests__/AmeliproDisclosure.spec.ts +79 -0
  88. package/src/components/Amelipro/AmeliproDisclosure/__tests__/__snapshots__/AmeliproDisclosure.spec.ts.snap +89 -0
  89. package/src/components/Amelipro/AmeliproFooter/AmeliproFooter.vue +6 -7
  90. package/src/components/Amelipro/AmeliproFooter/__tests__/AmeliproFooter.spec.ts +787 -0
  91. package/src/components/Amelipro/AmeliproFooter/__tests__/__snapshots__/AmeliproFooter.spec.ts.snap +318 -0
  92. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/__tests__/AmeliproHeaderBrandSection.spec.ts +167 -0
  93. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/__tests__/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +100 -0
  94. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/__tests__/AmeliproHeaderBar.spec.ts +312 -0
  95. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/__tests__/__snapshots__/AmeliproHeaderBar.spec.ts.snap +98 -0
  96. package/src/components/Amelipro/AmeliproHeader/__tests__/AmeliproHeader.spec.ts +361 -0
  97. package/src/components/Amelipro/AmeliproHeader/__tests__/__snapshots__/AmeliproHeader.spec.ts.snap +22 -0
  98. package/src/components/Amelipro/AmeliproMenu/__tests__/AmeliproMenu.spec.ts +168 -0
  99. package/src/components/Amelipro/AmeliproMenu/__tests__/__snapshots__/AmeliproMenu.spec.ts.snap +295 -0
  100. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/__tests__/AmeliproDropdownMenuBtn.spec.ts +128 -0
  101. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/__tests__/__snapshots__/AmeliproDropdownMenuBtn.spec.ts.snap +67 -0
  102. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/__tests__/AmeliproDropdownMenu.spec.ts +266 -0
  103. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/__tests__/__snapshots__/AmeliproDropdownMenu.spec.ts.snap +134 -0
  104. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/__tests__/AmeliproMessagingMenuBtn.spec.ts +72 -0
  105. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/__tests__/__snapshots__/AmeliproMessagingMenuBtn.spec.ts.snap +71 -0
  106. package/src/components/Amelipro/AmeliproPageLayout/tests/__snapshots__/AmeliproPageLayout.spec.ts.snap +12 -0
  107. package/src/components/Amelipro/AmeliproTable/AmeliproTable.stories.ts +81 -9
  108. package/src/components/Amelipro/AmeliproTable/AmeliproTable.vue +139 -61
  109. package/src/components/Amelipro/AmeliproTable/__tests__/AmeliproTable.spec.ts +10 -0
  110. package/src/components/Amelipro/AmeliproTable/__tests__/__snapshots__/AmeliproTable.spec.ts.snap +361 -187
  111. package/src/components/Amelipro/AmeliproTable/types.d.ts +11 -0
  112. package/src/components/Captcha/Captcha.mdx +72 -0
  113. package/src/components/Captcha/Captcha.stories.ts +276 -0
  114. package/src/components/Captcha/Captcha.vue +325 -0
  115. package/src/components/Captcha/CaptchaAlert.vue +60 -0
  116. package/src/components/Captcha/CaptchaBase.vue +219 -0
  117. package/src/components/Captcha/CaptchaBtn.vue +35 -0
  118. package/src/components/Captcha/CaptchaForm.vue +58 -0
  119. package/src/components/Captcha/CaptchaImg.vue +41 -0
  120. package/src/components/Captcha/CaptchaInformation.vue +64 -0
  121. package/src/components/Captcha/captchaApi.ts +111 -0
  122. package/src/components/Captcha/icons/volumeUp.vue +11 -0
  123. package/src/components/Captcha/locales.ts +35 -0
  124. package/src/components/Captcha/readme.md +5 -0
  125. package/src/components/Captcha/tests/Captcha.spec.ts +298 -0
  126. package/src/components/Captcha/tests/__snapshots__/Captcha.spec.ts.snap +716 -0
  127. package/src/components/Captcha/types.ts +2 -0
  128. package/src/components/Customs/Selects/SySelect/SySelect.vue +2 -2
  129. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +4 -0
  130. package/src/components/Customs/SyForm/SyForm.stories.ts +133 -23
  131. package/src/components/Customs/SyForm/SyForm.vue +17 -1
  132. package/src/components/Customs/SyTextField/SyTextField.vue +29 -7
  133. package/src/components/DatePicker/CalendarMode/DatePicker.vue +32 -9
  134. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +154 -18
  135. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +2 -2
  136. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +35 -4
  137. package/src/components/DatePicker/composables/tests/useDatePickerViewMode.spec.ts +107 -72
  138. package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +6 -6
  139. package/src/components/DatePicker/composables/useDatePickerViewMode.ts +57 -7
  140. package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +14 -14
  141. package/src/components/DatePicker/tests/navigation.regression.spec.ts +74 -0
  142. package/src/components/DatePicker/tests/navigation.simple.spec.ts +137 -0
  143. package/src/components/NirField/NirField.stories.ts +85 -2
  144. package/src/components/NirField/NirField.vue +55 -18
  145. package/src/components/NirField/locales.ts +1 -3
  146. package/src/components/PasswordField/PasswordField.vue +39 -7
  147. package/src/components/PhoneField/PhoneField.vue +43 -10
  148. package/src/components/RangeField/tests/RangeField.spec.ts +0 -3
  149. package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -0
  150. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +309 -0
  151. package/src/components/Tables/SyServerTable/SyServerTable.vue +18 -3
  152. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +67 -0
  153. package/src/components/Tables/SyTable/SyTable.mdx +15 -0
  154. package/src/components/Tables/SyTable/SyTable.stories.ts +228 -0
  155. package/src/components/Tables/SyTable/SyTable.vue +18 -3
  156. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +63 -0
  157. package/src/components/Tables/common/SyTablePagination.vue +10 -8
  158. package/src/components/Tables/common/types.ts +4 -0
  159. package/src/components/Tables/common/usePagination.ts +11 -20
  160. package/src/components/Tables/common/useTableCheckbox.ts +23 -11
  161. package/src/components/index.ts +1 -0
  162. package/src/composables/validation/AvecVosComposants.mdx.old +1 -1
  163. package/src/composables/validation/FormValidation.stories.ts.old +5 -5
  164. package/src/composables/validation/useFormValidation.ts +46 -8
  165. package/src/composables/validation/useValidatable.ts +19 -8
  166. package/src/stories/Accessibilite/Introduction.mdx +1 -1
  167. package/src/stories/Demarrer/EnrichirLeDesignSystem.mdx +43 -0
  168. package/src/stories/Demarrer/EnrichirLeDesignSystem.stories.ts +239 -0
  169. package/src/stories/Demarrer/SignalerUneAnomalie.mdx +39 -0
  170. package/src/stories/Demarrer/SignalerUneAnomalie.stories.ts +261 -0
  171. package/dist/main-DyEOPqqn.js +0 -33329
  172. package/src/components/Amelipro/AmeliproCheckbox/tests/AmeliproCheckbox.spec.ts +0 -19
  173. package/src/components/Amelipro/AmeliproCheckbox/tests/__snapshots__/AmeliproCheckbox.spec.ts.snap +0 -40
  174. package/src/components/Amelipro/AmeliproCheckboxGroup/tests/AmeliproCheckboxGroup.spec.ts +0 -46
  175. package/src/components/Amelipro/AmeliproChips/tests/AmeliproChips.spec.ts +0 -16
  176. package/src/components/Amelipro/AmeliproChips/tests/__snapshots__/AmeliproChips.spec.ts.snap +0 -97
  177. package/src/components/Amelipro/AmeliproDialog/tests/AmeliproDialog.spec.ts +0 -24
  178. package/src/components/Amelipro/AmeliproDialog/tests/__snapshots__/AmeliproDialog.spec.ts.snap +0 -134
  179. package/src/components/Amelipro/AmeliproDisclosure/tests/AmeliproDisclosure.spec.ts +0 -19
  180. package/src/components/Amelipro/AmeliproDisclosure/tests/__snapshots__/AmeliproDisclosure.spec.ts.snap +0 -104
  181. package/src/components/Amelipro/AmeliproFooter/tests/AmeliproFooter.spec.ts +0 -15
  182. package/src/components/Amelipro/AmeliproFooter/tests/__snapshots__/AmeliproFooter.spec.ts.snap +0 -432
  183. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/tests/AmeliproHeaderBrandSection.spec.ts +0 -15
  184. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/AmeliproHeaderBrandSection/tests/__snapshots__/AmeliproHeaderBrandSection.spec.ts.snap +0 -131
  185. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/tests/AmeliproHeaderBar.spec.ts +0 -15
  186. package/src/components/Amelipro/AmeliproHeader/AmeliproHeaderBar/tests/__snapshots__/AmeliproHeaderBar.spec.ts.snap +0 -172
  187. package/src/components/Amelipro/AmeliproHeader/tests/AmeliproHeader.spec.ts +0 -159
  188. package/src/components/Amelipro/AmeliproHeader/tests/__snapshots__/AmeliproHeader.spec.ts.snap +0 -841
  189. package/src/components/Amelipro/AmeliproMenu/tests/AmeliproMenu.spec.ts +0 -85
  190. package/src/components/Amelipro/AmeliproMenu/tests/__snapshots__/AmeliproMenu.spec.ts.snap +0 -537
  191. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/tests/AmeliproDropdownMenuBtn.spec.ts +0 -16
  192. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/AmeliproDropdownMenuBtn/tests/__snapshots__/AmeliproDropdownMenuBtn.spec.ts.snap +0 -56
  193. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/tests/AmeliproDropdownMenu.spec.ts +0 -28
  194. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproDropdownMenu/tests/__snapshots__/AmeliproDropdownMenu.spec.ts.snap +0 -300
  195. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/tests/AmeliproMessagingMenuBtn.spec.ts +0 -16
  196. package/src/components/Amelipro/AmeliproMessagingLayout/AmeliproMessagingMenuBtn/tests/__snapshots__/AmeliproMessagingMenuBtn.spec.ts.snap +0 -89
  197. package/src/components/BackBtn/tests/__snapshots__/BackBtn.spec.ts.snap +0 -45
  198. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +0 -1270
  199. package/src/stories/Demarrer/CreerUneIssue.mdx +0 -67
  200. 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
@@ -63,6 +63,7 @@ export { default as SySelect } from './Customs/Selects/SySelect/SySelect.vue'
63
63
  export { default as SyTextArea } from './SyTextArea/SyTextArea.vue'
64
64
  export { default as SyTextField } from './Customs/SyTextField/SyTextField.vue'
65
65
  export { default as UploadWorkflow } from './UploadWorkflow/UploadWorkflow.vue'
66
+ export { default as Captcha } from './Captcha/Captcha.vue'
66
67
  export { default as SyForm } from './Customs/SyForm/SyForm.vue'
67
68
 
68
69
  // ===========================
@@ -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() {