@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.
Files changed (217) hide show
  1. package/README.md +1 -1
  2. package/dist/{DateFilter-BmRuzQ9Z.js → DateFilter-YWOTbfeL.js} +1 -1
  3. package/dist/{NumberFilter-CnIPDHqx.js → NumberFilter-DMmMgALM.js} +1 -1
  4. package/dist/{PeriodFilter-CZwZ8CnQ.js → PeriodFilter-Bok5BHcn.js} +1 -1
  5. package/dist/SelectFilter-BKud2WhN.js +136 -0
  6. package/dist/{TextFilter-DTxZHJwX.js → TextFilter-DvMf2thH.js} +1 -1
  7. package/dist/components/Accordion/Accordion.d.ts +2 -1
  8. package/dist/components/Accordion/composables/useAccordionGroupCommunication.d.ts +5 -0
  9. package/dist/components/Accordion/composables/useAccordionKeyboardNavigation.d.ts +12 -0
  10. package/dist/components/Accordion/composables/useAccordionState.d.ts +13 -0
  11. package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +85 -0
  12. package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
  13. package/dist/components/Customs/SySelect/SySelect.d.ts +33 -13
  14. package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -2
  15. package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +1585 -1452
  16. package/dist/components/DatePicker/DatePicker/DatePicker.d.ts +16 -2
  17. package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +3 -1
  18. package/dist/components/DatePicker/composables/index.d.ts +2 -0
  19. package/dist/components/DatePicker/composables/useAsteriskDisplay.d.ts +14 -0
  20. package/dist/components/DatePicker/composables/useDateAutoClamp.d.ts +16 -0
  21. package/dist/components/DatePicker/composables/useDateRangeInput.d.ts +1 -1
  22. package/dist/components/DatePicker/composables/useDisplayedDateString.d.ts +3 -0
  23. package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +1 -0
  24. package/dist/components/DatePicker/composables/useMonthButtonCustomization.d.ts +5 -2
  25. package/dist/components/NirField/NirField.d.ts +7 -3
  26. package/dist/components/NirField/nirValidation.d.ts +1 -1
  27. package/dist/components/PasswordField/PasswordField.d.ts +2 -0
  28. package/dist/components/PeriodField/PeriodField.d.ts +52 -8
  29. package/dist/components/PhoneField/PhoneField.d.ts +2 -2
  30. package/dist/components/RangeField/RangeField.d.ts +2 -0
  31. package/dist/components/SearchListField/SearchListField.d.ts +9 -0
  32. package/dist/components/SyTextArea/SyTextArea.d.ts +2 -0
  33. package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +14 -9
  34. package/dist/components/Tables/SyTable/SyTable.d.ts +12 -7
  35. package/dist/components/Tables/common/SyTablePagination.d.ts +1636 -0
  36. package/dist/components/Tables/common/TableHeader.d.ts +2 -20
  37. package/dist/components/Tables/common/filters/SelectFilter.d.ts +5 -5
  38. package/dist/components/Tables/common/filters/getFilterComponent.d.ts +1 -0
  39. package/dist/components/Tables/common/filters/locales.d.ts +4 -0
  40. package/dist/components/Tables/common/filters/logics/date.d.ts +1 -0
  41. package/dist/components/Tables/common/filters/logics/number.d.ts +1 -0
  42. package/dist/components/Tables/common/filters/logics/period.d.ts +1 -0
  43. package/dist/components/Tables/common/filters/logics/select.d.ts +1 -0
  44. package/dist/components/Tables/common/filters/logics/text.d.ts +1 -0
  45. package/dist/components/Tables/common/locales.d.ts +21 -0
  46. package/dist/components/Tables/common/organizeColumns/OrganizeColumns.d.ts +267 -0
  47. package/dist/components/Tables/common/organizeColumns/sortHeaders.d.ts +2 -0
  48. package/dist/components/Tables/common/tableFilterUtils.d.ts +1 -0
  49. package/dist/components/Tables/common/tableStorageUtils.d.ts +41 -1
  50. package/dist/components/Tables/common/tableUtils.d.ts +42 -5
  51. package/dist/components/Tables/common/types.d.ts +19 -8
  52. package/dist/components/Tables/common/usePagination.d.ts +22 -0
  53. package/dist/components/Tables/common/useTableCheckbox.d.ts +20 -0
  54. package/dist/components/Tables/common/useTableHeaders.d.ts +76 -0
  55. package/dist/components/Tables/common/useTableItems.d.ts +24 -0
  56. package/dist/components/Tables/common/useTableOptions.d.ts +18 -0
  57. package/dist/components/ToolbarContainer/ToolbarContainer.d.ts +11 -0
  58. package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +9 -2
  59. package/dist/components/index.d.ts +8 -6
  60. package/dist/design-system-v3.js +58 -56
  61. package/dist/design-system-v3.umd.cjs +22 -22
  62. package/dist/main-Cx8qG7YR.js +16344 -0
  63. package/dist/stories/Accessibilite/Vuetify/VuetifyItems.d.ts +14 -2
  64. package/dist/stories/DesignTokens/StylesTypographiques.stories.new.d.ts +8 -0
  65. package/dist/stories/DesignTokens/TypographyDisplay.d.ts +28 -0
  66. package/dist/stories/DesignTokens/vue-shims.d.ts +6 -0
  67. package/dist/style.css +1 -1
  68. package/package.json +1 -1
  69. package/src/common/imgs/accessibility-svgrepo-com.svg +4 -0
  70. package/src/components/Accordion/Accessibilite/AccessibilityGuide.mdx +249 -0
  71. package/src/components/Accordion/Accordion.vue +48 -76
  72. package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +146 -0
  73. package/src/components/Accordion/composables/__tests__/useAccordionKeyboardNavigation.spec.ts +209 -0
  74. package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +144 -0
  75. package/src/components/Accordion/composables/useAccordionGroupCommunication.ts +52 -0
  76. package/src/components/Accordion/composables/useAccordionKeyboardNavigation.ts +111 -0
  77. package/src/components/Accordion/composables/useAccordionState.ts +59 -0
  78. package/src/components/Accordion/tests/__snapshots__/accordion.spec.ts.snap +3 -0
  79. package/src/components/Customs/SyCheckbox/Accessibilite.mdx +303 -0
  80. package/src/components/Customs/SyCheckbox/SyCheckbox.mdx +50 -0
  81. package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +630 -0
  82. package/src/components/Customs/SyCheckbox/SyCheckbox.vue +326 -0
  83. package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +201 -0
  84. package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +1 -0
  85. package/src/components/Customs/SyInputSelect/SyInputSelect.vue +8 -1
  86. package/src/components/Customs/SySelect/SySelect.stories.ts +160 -0
  87. package/src/components/Customs/SySelect/SySelect.vue +291 -32
  88. package/src/components/Customs/SySelect/tests/SySelect.spec.ts +230 -0
  89. package/src/components/Customs/SyTextField/SyTextField.stories.ts +3 -2
  90. package/src/components/Customs/SyTextField/SyTextField.vue +19 -8
  91. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +241 -31
  92. package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +305 -57
  93. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.events.spec.ts +161 -0
  94. package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +4 -2
  95. package/src/components/DatePicker/DatePicker/DatePicker.stories.ts +259 -137
  96. package/src/components/DatePicker/DatePicker/DatePicker.vue +153 -25
  97. package/src/components/DatePicker/DatePicker/tests/DatePicker.events.spec.ts +189 -0
  98. package/src/components/DatePicker/DatePicker/{DatePicker.spec.ts → tests/DatePicker.spec.ts} +1 -15
  99. package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +24 -14
  100. package/src/components/DatePicker/DateTextInput/DateTextInput.events.spec.ts +148 -0
  101. package/src/components/DatePicker/DateTextInput/DateTextInput.spec.ts +3 -1
  102. package/src/components/DatePicker/DateTextInput/DateTextInput.vue +200 -5
  103. package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +241 -31
  104. package/src/components/DatePicker/composables/index.ts +2 -0
  105. package/src/components/DatePicker/composables/tests/useDateAutoClamp.spec.ts +190 -0
  106. package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +182 -4
  107. package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +105 -80
  108. package/src/components/DatePicker/composables/useAsteriskDisplay.ts +31 -0
  109. package/src/components/DatePicker/composables/useDateAutoClamp.ts +136 -0
  110. package/src/components/DatePicker/composables/useDateRangeInput.ts +21 -18
  111. package/src/components/DatePicker/composables/useDisplayedDateString.ts +13 -1
  112. package/src/components/DatePicker/composables/useInputBlurHandler.ts +84 -20
  113. package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +149 -51
  114. package/src/components/DiacriticPicker/DiacriticPicker.stories.ts +10 -0
  115. package/src/components/ErrorPage/Accessibilite.stories.ts +8 -0
  116. package/src/components/ErrorPage/ErrorPage.vue +12 -6
  117. package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +4 -4
  118. package/src/components/NirField/NirField.mdx +22 -9
  119. package/src/components/NirField/NirField.stories.ts +26 -2
  120. package/src/components/NirField/NirField.vue +209 -22
  121. package/src/components/NirField/nirValidation.ts +17 -3
  122. package/src/components/NirField/tests/NirField.spec.ts +2 -2
  123. package/src/components/NotFoundPage/Accessibilite.stories.ts +8 -0
  124. package/src/components/NotFoundPage/NotFoundPage.vue +2 -1
  125. package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +8 -6
  126. package/src/components/PaginatedTable/PaginatedTable.mdx +2 -0
  127. package/src/components/PasswordField/PasswordField.stories.ts +4 -0
  128. package/src/components/PasswordField/PasswordField.vue +3 -0
  129. package/src/components/PeriodField/PeriodField.vue +2 -0
  130. package/src/components/PhoneField/PhoneField.stories.ts +15 -15
  131. package/src/components/PhoneField/PhoneField.vue +1 -1
  132. package/src/components/RangeField/RangeField.stories.ts +9 -0
  133. package/src/components/RangeField/RangeField.vue +4 -0
  134. package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +12 -0
  135. package/src/components/SearchListField/SearchListField.vue +5 -0
  136. package/src/components/SyTextArea/SyTextArea.vue +3 -0
  137. package/src/components/SyTextArea/tests/SyTextArea.spec.ts +0 -1
  138. package/src/components/Tables/SyServerTable/FilterRules.stories.ts +632 -15
  139. package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -5
  140. package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +2844 -1377
  141. package/src/components/Tables/SyServerTable/SyServerTable.vue +155 -66
  142. package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +256 -4
  143. package/src/components/Tables/SyTable/FilterRules.stories.ts +183 -0
  144. package/src/components/Tables/SyTable/SyTable.mdx +14 -4
  145. package/src/components/Tables/SyTable/SyTable.stories.ts +1265 -477
  146. package/src/components/Tables/SyTable/SyTable.vue +152 -72
  147. package/src/components/Tables/SyTable/tests/SyTable.spec.ts +366 -4
  148. package/src/components/Tables/common/SyTableFilter.vue +3 -56
  149. package/src/components/Tables/common/SyTablePagination.vue +375 -0
  150. package/src/components/Tables/common/TableHeader.vue +10 -26
  151. package/src/components/Tables/common/filters/SelectFilter.vue +131 -22
  152. package/src/components/Tables/common/filters/getFilterComponent.ts +54 -0
  153. package/src/components/Tables/common/filters/locales.ts +4 -0
  154. package/src/components/Tables/common/filters/logics/date.ts +12 -0
  155. package/src/components/Tables/common/filters/logics/number.ts +48 -0
  156. package/src/components/Tables/common/filters/logics/period.ts +25 -0
  157. package/src/components/Tables/common/filters/logics/select.ts +27 -0
  158. package/src/components/Tables/common/filters/logics/tests/TextFilterLogic.spec.ts +177 -0
  159. package/src/components/Tables/common/filters/logics/text.ts +62 -0
  160. package/src/components/Tables/common/filters/tests/TextFilter.spec.ts +11 -11
  161. package/src/components/Tables/common/locales.ts +24 -0
  162. package/src/components/Tables/common/organizeColumns/OrganizeColumns.vue +269 -0
  163. package/src/components/Tables/common/organizeColumns/sortHeaders.ts +9 -0
  164. package/src/components/Tables/common/tableFilterUtils.ts +43 -295
  165. package/src/components/Tables/common/tableStorageUtils.ts +27 -2
  166. package/src/components/Tables/common/tableStyles.scss +26 -0
  167. package/src/components/Tables/common/tableUtils.ts +3 -16
  168. package/src/components/Tables/common/tests/SyTablePagination.spec.ts +170 -0
  169. package/src/components/Tables/common/tests/filterByRange.spec.ts +215 -0
  170. package/src/components/Tables/common/tests/tableFilterUtils.spec.ts +0 -14
  171. package/src/components/Tables/common/tests/tableUtils.spec.ts +7 -51
  172. package/src/components/Tables/common/types.ts +17 -6
  173. package/src/components/Tables/common/usePagination.ts +83 -0
  174. package/src/components/Tables/common/useTableCheckbox.ts +58 -0
  175. package/src/components/Tables/common/useTableHeaders.ts +88 -0
  176. package/src/components/Tables/common/useTableItems.ts +87 -0
  177. package/src/components/Tables/common/useTableOptions.ts +93 -0
  178. package/src/components/ToolbarContainer/ToolbarContainer.mdx +16 -0
  179. package/src/components/ToolbarContainer/ToolbarContainer.stories.ts +675 -0
  180. package/src/components/ToolbarContainer/ToolbarContainer.vue +128 -0
  181. package/src/components/ToolbarContainer/tests/ToolbarContainer.spec.ts +156 -0
  182. package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +74 -0
  183. package/src/components/UserMenuBtn/UserMenuBtn.vue +19 -17
  184. package/src/components/index.ts +8 -6
  185. package/src/stories/Accessibilite/Aculturation/AuditDesignSystem.mdx +293 -20
  186. package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +448 -54
  187. package/src/stories/Accessibilite/Audit/RGAA.mdx +231 -23
  188. package/src/stories/Accessibilite/Avancement/Avancement.mdx +591 -7
  189. package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +139 -38
  190. package/src/stories/Accessibilite/Introduction.mdx +258 -18
  191. package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +221 -31
  192. package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +204 -22
  193. package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +537 -24
  194. package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +577 -70
  195. package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru.mdx +382 -31
  196. package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +419 -81
  197. package/src/stories/Accessibilite/Vuetify/Vuetify.mdx +132 -6
  198. package/src/stories/Accessibilite/Vuetify/Vuetify.stories.ts +370 -146
  199. package/src/stories/Accessibilite/Vuetify/VuetifyItems.ts +35 -57
  200. package/src/stories/Demarrer/Accueil.stories.ts +20 -5
  201. package/src/stories/DesignTokens/StylesTypographiques.mdx +10 -9
  202. package/src/stories/DesignTokens/StylesTypographiques.stories.new.ts +397 -0
  203. package/src/stories/DesignTokens/StylesTypographiques.stories.ts +397 -0
  204. package/src/stories/DesignTokens/TypographyDisplay.vue +155 -0
  205. package/src/stories/DesignTokens/vue-shims.d.ts +6 -0
  206. package/src/stories/GuideDuDev/LesBreackingChanges.mdx +0 -2
  207. package/src/stories/GuideDuDev/MigrationDepuisBridge.mdx +1 -1
  208. package/src/stories/GuideDuDev/MigrationDepuisVue2.mdx +1 -1
  209. package/src/stories/GuideDuDev/PortailAgent.mdx +10 -0
  210. package/src/stories/GuideDuDev/PortailAgent.stories.ts +506 -0
  211. package/src/stories/GuideDuDev/Theme.mdx +41 -0
  212. package/dist/SelectFilter-Cj-GW2Cc.js +0 -97
  213. package/dist/main-WDqeoGM-.js +0 -14788
  214. package/src/components/PaginatedTable/tests/__snapshots__/PaginatedTable.spec.ts.snap +0 -886
  215. package/src/components/Tables/SyServerTable/tests/__snapshots__/SyServerTable.spec.ts.snap +0 -521
  216. package/src/components/Tables/SyTable/tests/__snapshots__/SyTable.spec.ts.snap +0 -521
  217. package/src/stories/DesignTokens/ThemePA.mdx +0 -35
@@ -1,16 +1,23 @@
1
1
  <script setup lang="ts">
2
- import { computed, ref, useAttrs, watch, provide, nextTick } from 'vue'
2
+ import { computed, onMounted, nextTick, provide, ref, toRef, useAttrs, watch } from 'vue'
3
3
  import type { VDataTableServer } from 'vuetify/components'
4
+ import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue'
4
5
  import SyTableFilter from '../common/SyTableFilter.vue'
5
6
  import TableHeader from '../common/TableHeader.vue'
7
+ import SyTablePagination from '../common/SyTablePagination.vue'
6
8
  import { processItems } from '../common/formatters'
7
9
  import { locales } from '../common/locales'
8
10
  import { useTableUtils } from '../common/tableUtils'
9
- import type { DataOptions, FilterOption, SyServerTableProps, TableColumnHeader } from '../common/types'
11
+ import type { DataOptions, SyServerTableProps } from '../common/types'
10
12
  import { useTableFilter } from '../common/useTableFilter'
13
+ import { usePagination } from '../common/usePagination'
14
+ import { useTableOptions } from '../common/useTableOptions'
15
+ import { useTableHeaders } from '../common/useTableHeaders'
16
+ import { useTableItems } from '../common/useTableItems'
17
+ import OrganizeColumns from '../common/organizeColumns/OrganizeColumns.vue'
18
+ import { useTableCheckbox } from '../common/useTableCheckbox'
11
19
 
12
20
  const props = withDefaults(defineProps<SyServerTableProps>(), {
13
- itemsPerPage: undefined,
14
21
  caption: '',
15
22
  showFilters: false,
16
23
  items: () => [],
@@ -19,31 +26,32 @@
19
26
  filterInputConfig: () => ({}),
20
27
  density: 'default',
21
28
  striped: false,
29
+ showSelect: false,
22
30
  })
23
31
 
32
+ const emit = defineEmits<{
33
+ (e: 'update:options', options: Partial<DataOptions>): void
34
+ }>()
35
+
24
36
  const options = defineModel<Partial<DataOptions>>('options', {
25
37
  required: false,
26
38
  default: () => ({}),
27
39
  })
28
40
 
29
- const table = ref<VDataTableServer>()
30
-
31
- // Computed pour les filtres
32
- const filters = computed({
33
- get: () => options.value.filters || [],
34
- set: (newFilters: FilterOption[]) => {
35
- options.value = {
36
- ...options.value,
37
- filters: newFilters,
38
- }
39
- },
41
+ const model = defineModel<unknown[]>('modelValue', {
42
+ required: false,
43
+ default: () => [],
40
44
  })
41
45
 
42
- // Récupère la fonction filterItems du composable
43
- // Cela peut être utilisé pour la prévisualisation du filtrage côté client ou pour les tests
46
+ const table = ref<VDataTableServer>()
47
+
48
+ // Get filter utilities
44
49
  const { filterItems } = useTableFilter()
45
50
 
46
- defineExpose({ filterItems })
51
+ // Use the table options composable
52
+ const { filters } = useTableOptions({
53
+ options,
54
+ })
47
55
 
48
56
  const componentAttributes = useAttrs()
49
57
 
@@ -57,11 +65,11 @@
57
65
  setupLocalStorage,
58
66
  columnWidths,
59
67
  updateColumnWidth,
68
+ headers: storageHeaders,
60
69
  } = useTableUtils({
61
70
  tableId: uniqueTableId.value,
62
71
  prefix: 'server-table',
63
72
  suffix: props.suffix,
64
- itemsPerPage: props.itemsPerPage,
65
73
  caption: props.caption,
66
74
  serverItemsLength: props.serverItemsLength,
67
75
  componentAttributes,
@@ -69,9 +77,80 @@
69
77
  density: props.density,
70
78
  })
71
79
 
80
+ // Use the table headers composable
81
+ const { headers, displayHeaders, getEnhancedHeader } = useTableHeaders({
82
+ headersProp: storageHeaders.value ? storageHeaders : toRef(props, 'headers'),
83
+ filterInputConfig: props.filterInputConfig,
84
+ })
85
+
86
+ // Create a reactive reference for items
87
+ const itemsRef = computed(() => props.items)
88
+
89
+ // For server-side tables, we don't use the filteredItems from useTableItems
90
+ // Instead, we use the items directly from props as they are already filtered server-side
91
+ // But we still need the createEmptyItemWithStructure function
92
+ const { createEmptyItemWithStructure } = useTableItems({
93
+ items: itemsRef,
94
+ headers,
95
+ filters,
96
+ options,
97
+ filterItems,
98
+ })
99
+
100
+ // Use the pagination composable with serverItemsLength
101
+ const itemsLength = computed(() => props.serverItemsLength)
102
+ const { page, pageCount, itemsPerPageValue, updateItemsPerPage } = usePagination({
103
+ options,
104
+ itemsLength,
105
+ table,
106
+ emit,
107
+ })
108
+
109
+ // Create a computed property for items to ensure reactivity
110
+ const tableItems = computed(() => props.items)
111
+
112
+ // Function to add accessibility attributes to row checkboxes
113
+ const accessibilityRowCheckboxes = () => {
114
+ nextTick(() => {
115
+ setTimeout(() => {
116
+ const tableElement = document.getElementById(uniqueTableId.value)
117
+ if (!tableElement) return
118
+
119
+ // Find all row checkboxes
120
+ const rowCheckboxes = tableElement.querySelectorAll('td .v-selection-control input[type="checkbox"]')
121
+ rowCheckboxes.forEach((checkbox, index) => {
122
+ const rowLabel = `${locales.selectRow} ${index + 1}`
123
+ checkbox.setAttribute('aria-label', rowLabel)
124
+ checkbox.setAttribute('title', rowLabel)
125
+ })
126
+ }, 100) // Small delay to ensure DOM is updated
127
+ })
128
+ }
129
+
130
+ // Watch for changes that might affect the table and update accessibility
131
+ watch(() => props.items, accessibilityRowCheckboxes, { deep: true })
132
+ watch(() => props.serverItemsLength, accessibilityRowCheckboxes)
133
+ watch(() => page.value, accessibilityRowCheckboxes)
134
+
135
+ // Apply accessibility attributes when component is mounted
136
+ onMounted(() => {
137
+ accessibilityRowCheckboxes()
138
+ })
139
+
140
+ // Use the table checkbox composable
141
+ const { getItemValue, toggleAllRows } = useTableCheckbox({
142
+ items: tableItems,
143
+ modelValue: model,
144
+ updateModelValue: (value) => {
145
+ model.value = value
146
+ },
147
+ })
148
+
149
+ defineExpose({ filterItems })
150
+
72
151
  setupAccessibility()
73
152
 
74
- const { watchOptions } = setupLocalStorage()
153
+ const { watchOptions, saveHeaders } = setupLocalStorage()
75
154
 
76
155
  // Create a reactive reference to column widths that will be provided to children
77
156
  const reactiveColumnWidths = ref(columnWidths.value)
@@ -108,47 +187,14 @@
108
187
  { deep: true },
109
188
  )
110
189
 
111
- // Fonction pour améliorer les en-têtes de colonnes avec les types de filtres appropriés
112
- function getEnhancedHeader(column: TableColumnHeader): TableColumnHeader {
113
- // Trouve l'en-tête correspondant dans les props si disponible
114
- const matchingHeader = props.headers?.find(h => h.key === column.key || h.value === column.value)
115
-
116
- // Crée un en-tête amélioré avec les types appropriés
117
- return {
118
- ...column,
119
- title: column.name || matchingHeader?.title,
120
- filterType: column.filterType || matchingHeader?.filterType,
121
- filterOptions: column.filterOptions || matchingHeader?.filterOptions,
122
- filterable: matchingHeader?.filterable !== undefined ? matchingHeader.filterable : column.filterable,
123
- } as TableColumnHeader
124
- }
190
+ watch(
191
+ headers,
192
+ () => {
193
+ saveHeaders(headers.value)
194
+ },
195
+ { deep: true },
196
+ )
125
197
 
126
- // Fonction pour créer un élément vide qui maintient la structure des colonnes
127
- function createEmptyItemWithStructure(): Record<string, unknown>[] {
128
- // Si nous avons des éléments, utilise le premier élément comme modèle
129
- if (props.items.length > 0) {
130
- // Crée un objet vide avec les mêmes clés que le premier élément
131
- const template = Object.keys(props.items[0]).reduce((obj, key) => {
132
- obj[key] = ''
133
- return obj
134
- }, {} as Record<string, unknown>)
135
- return [template]
136
- }
137
-
138
- // Si nous avons des en-têtes, les utilise pour créer une structure
139
- if (props.headers && props.headers.length > 0) {
140
- // Crée un objet vide avec les clés des en-têtes
141
- const template = props.headers.reduce((obj, header) => {
142
- const key = header.key || header.value || ''
143
- if (key) obj[key] = ''
144
- return obj
145
- }, {} as Record<string, unknown>)
146
- return [template]
147
- }
148
-
149
- // Repli vers un objet vide
150
- return [{}]
151
- }
152
198
  </script>
153
199
 
154
200
  <template>
@@ -159,10 +205,15 @@
159
205
  <VDataTableServer
160
206
  ref="table"
161
207
  v-bind="propsFacade"
208
+ v-model="model"
209
+ :headers="displayHeaders"
162
210
  color="primary"
163
211
  :items="processItems(props.items.length > 0 ? props.items : createEmptyItemWithStructure())"
164
212
  :items-length="props.serverItemsLength || 0"
165
213
  :density="props.density"
214
+ :show-select="props.showSelect"
215
+ :item-selectable="(item) => true"
216
+ :item-value="getItemValue"
166
217
  @update:options="updateOptions"
167
218
  >
168
219
  <template #top>
@@ -182,12 +233,31 @@
182
233
  :key="column.key"
183
234
  >
184
235
  <th>
185
- <TableHeader
186
- :table="table"
187
- :header-params="slotProps as any"
188
- :column="column"
189
- :resizable-columns="props.resizableColumns"
190
- />
236
+ <template v-if="column.key === 'data-table-select' && props.showSelect">
237
+ <SyCheckbox
238
+ :model-value="slotProps.allSelected"
239
+ :indeterminate="slotProps.someSelected && !slotProps.allSelected"
240
+ color="primary"
241
+ density="compact"
242
+ hide-details
243
+ :is-header="true"
244
+ :aria-label="locales.selectAllRows"
245
+ :title="locales.selectAllRows"
246
+ @click="toggleAllRows"
247
+ >
248
+ <template #label>
249
+ <span class="d-sr-only">{{ locales.selectAllRows }}</span>
250
+ </template>
251
+ </SyCheckbox>
252
+ </template>
253
+ <template v-else>
254
+ <TableHeader
255
+ :table="table"
256
+ :header-params="slotProps"
257
+ :column="column"
258
+ :resizable-columns="props.resizableColumns"
259
+ />
260
+ </template>
191
261
  </th>
192
262
  </template>
193
263
  </tr>
@@ -195,8 +265,9 @@
195
265
  v-if="props.showFilters"
196
266
  class="filters"
197
267
  >
268
+ <th v-if="props.showSelect" />
198
269
  <template
199
- v-for="column in slotProps.columns"
270
+ v-for="column in slotProps.columns.filter(c => c.key !== 'data-table-select')"
200
271
  :key="column.key"
201
272
  >
202
273
  <th>
@@ -278,6 +349,24 @@
278
349
  </tr>
279
350
  </template>
280
351
  </template>
352
+
353
+ <template #bottom>
354
+ <div class="d-flex align-center pa-2">
355
+ <OrganizeColumns
356
+ v-if="props.enableColumnControls && headers"
357
+ v-model:headers="headers"
358
+ />
359
+ <SyTablePagination
360
+ v-if="props.serverItemsLength > 0"
361
+ :page="page"
362
+ :items-per-page="itemsPerPageValue"
363
+ :page-count="pageCount"
364
+ :items-length="props.serverItemsLength"
365
+ @update:page="page = $event"
366
+ @update:items-per-page="updateItemsPerPage"
367
+ />
368
+ </div>
369
+ </template>
281
370
  </VDataTableServer>
282
371
  </div>
283
372
  </template>
@@ -1,4 +1,4 @@
1
- import { describe, it, expect, vi, afterEach } from 'vitest'
1
+ import { describe, it, expect, vi, afterEach, beforeAll } from 'vitest'
2
2
  import { mount } from '@vue/test-utils'
3
3
 
4
4
  import { vuetify } from '@tests/unit/setup'
@@ -28,7 +28,15 @@ const fakeItems = [
28
28
  },
29
29
  ]
30
30
 
31
- const headers = [
31
+ // Define a more complete DataTableHeaders type for testing
32
+ interface TestDataTableHeader {
33
+ title: string
34
+ key: string
35
+ hidden?: boolean
36
+ order?: number
37
+ }
38
+
39
+ const headers: TestDataTableHeader[] = [
32
40
  {
33
41
  title: 'ID',
34
42
  key: 'id',
@@ -44,6 +52,24 @@ const headers = [
44
52
  ]
45
53
 
46
54
  describe('SyServerTable', () => {
55
+ beforeAll(() => {
56
+ // Mock visualViewport for Vuetify's VMenu component
57
+ global.visualViewport = {
58
+ width: 1024,
59
+ height: 768,
60
+ scale: 1,
61
+ offsetLeft: 0,
62
+ offsetTop: 0,
63
+ pageLeft: 0,
64
+ pageTop: 0,
65
+ addEventListener: vi.fn(),
66
+ removeEventListener: vi.fn(),
67
+ dispatchEvent: vi.fn(),
68
+ onresize: null,
69
+ onscroll: null,
70
+ }
71
+ })
72
+
47
73
  afterEach(() => {
48
74
  vi.resetAllMocks()
49
75
  })
@@ -168,9 +194,8 @@ describe('SyServerTable', () => {
168
194
  it('passes itemsPerPage prop correctly', () => {
169
195
  const wrapper = mount(SyServerTable, {
170
196
  props: {
171
- options: {} as DataOptions,
197
+ options: { itemsPerPage: 5 } as DataOptions,
172
198
  serverItemsLength: 10,
173
- itemsPerPage: 5,
174
199
  suffix: 'test',
175
200
  },
176
201
  attrs: {
@@ -447,4 +472,231 @@ describe('SyServerTable', () => {
447
472
  expect(customFilterSlot.exists()).toBe(true)
448
473
  expect(customFilterSlot.text()).toBe(customSlotText)
449
474
  })
475
+
476
+ describe('SyServerTable Checkbox Selection', () => {
477
+ it('enables selection when showSelect is true', async () => {
478
+ const wrapper = mount(SyServerTable, {
479
+ props: {
480
+ headers,
481
+ items: fakeItems,
482
+ serverItemsLength: fakeItems.length,
483
+ showSelect: true,
484
+ suffix: '',
485
+ },
486
+ global: {
487
+ plugins: [vuetify],
488
+ },
489
+ })
490
+
491
+ // Check that the VDataTableServer has showSelect prop set to true
492
+ const dataTable = wrapper.findComponent({ name: 'VDataTableServer' })
493
+ expect(dataTable.props('showSelect')).toBe(true)
494
+ })
495
+
496
+ it('disables selection when showSelect is false', async () => {
497
+ const wrapper = mount(SyServerTable, {
498
+ props: {
499
+ headers,
500
+ items: fakeItems,
501
+ serverItemsLength: fakeItems.length,
502
+ showSelect: false,
503
+ suffix: '',
504
+ },
505
+ global: {
506
+ plugins: [vuetify],
507
+ },
508
+ })
509
+
510
+ // Check that the VDataTableServer has showSelect prop set to false
511
+ const dataTable = wrapper.findComponent({ name: 'VDataTableServer' })
512
+ expect(dataTable.props('showSelect')).toBe(false)
513
+ })
514
+
515
+ it('passes the correct item-value function to the data table', async () => {
516
+ const wrapper = mount(SyServerTable, {
517
+ props: {
518
+ headers,
519
+ items: fakeItems,
520
+ serverItemsLength: fakeItems.length,
521
+ showSelect: true,
522
+ suffix: '',
523
+ },
524
+ global: {
525
+ plugins: [vuetify],
526
+ },
527
+ })
528
+
529
+ // Access the internal getItemValue function
530
+ // Since it's not exposed, we'll test the selection behavior instead
531
+ const dataTable = wrapper.findComponent({ name: 'VDataTableServer' })
532
+ expect(dataTable.props('itemValue')).toBeDefined()
533
+
534
+ // Instead of testing the internal function directly, we'll verify the component works correctly
535
+ // by checking if the data table has the correct props
536
+ expect(dataTable.props('showSelect')).toBe(true)
537
+ })
538
+
539
+ it('properly binds the v-model for selection', async () => {
540
+ const selectedItems = [fakeItems[0].id, fakeItems[2].id]
541
+ const wrapper = mount(SyServerTable, {
542
+ props: {
543
+ headers,
544
+ items: fakeItems,
545
+ serverItemsLength: fakeItems.length,
546
+ showSelect: true,
547
+ modelValue: selectedItems,
548
+ suffix: '',
549
+ },
550
+ global: {
551
+ plugins: [vuetify],
552
+ },
553
+ })
554
+
555
+ // Check that the VDataTableServer has the correct model value
556
+ const dataTable = wrapper.findComponent({ name: 'VDataTableServer' })
557
+ expect(dataTable.props('modelValue')).toEqual(selectedItems)
558
+ })
559
+
560
+ it('exposes the toggleAllRows method', async () => {
561
+ const wrapper = mount(SyServerTable, {
562
+ props: {
563
+ headers,
564
+ 'items': fakeItems,
565
+ 'serverItemsLength': fakeItems.length,
566
+ 'showSelect': true,
567
+ 'modelValue': [],
568
+ 'suffix': '',
569
+ 'onUpdate:modelValue': (val: unknown[]) => {
570
+ wrapper.setProps({ modelValue: val })
571
+ },
572
+ },
573
+ global: {
574
+ plugins: [vuetify],
575
+ },
576
+ })
577
+
578
+ // Since toggleAllRows is not exposed, we'll test if the component renders correctly
579
+ // and has the expected structure for selection
580
+ const dataTable = wrapper.findComponent({ name: 'VDataTableServer' })
581
+ expect(dataTable.props('showSelect')).toBe(true)
582
+ })
583
+ })
584
+
585
+ describe('Column management', () => {
586
+ it('should hide a column when hideColumn is called', async () => {
587
+ // Create a mock for OrganizeColumns component
588
+ const mockOrganizeColumns = {
589
+ name: 'OrganizeColumns',
590
+ props: ['headers'],
591
+ template: '<div></div>',
592
+ emits: ['update:headers'],
593
+ }
594
+
595
+ // Create test items that will ensure all columns are rendered
596
+ const testItems = [
597
+ { id: 1, name: 'Test 1', age: 25 },
598
+ { id: 2, name: 'Test 2', age: 30 },
599
+ ]
600
+
601
+ const wrapper = mount(SyServerTable, {
602
+ props: {
603
+ options: {} as DataOptions,
604
+ suffix: 'test',
605
+ headers: [...headers],
606
+ items: testItems,
607
+ serverItemsLength: testItems.length,
608
+ enableColumnControls: true,
609
+ },
610
+ global: {
611
+ plugins: [vuetify],
612
+ stubs: {
613
+ OrganizeColumns: mockOrganizeColumns,
614
+ },
615
+ },
616
+ attachTo: document.body, // Attach to DOM for better rendering
617
+ })
618
+
619
+ // Get the OrganizeColumns component
620
+ const organizeColumnsComponent = wrapper.findComponent({ name: 'OrganizeColumns' })
621
+ expect(organizeColumnsComponent.exists()).toBe(true)
622
+
623
+ // Verify initial column count
624
+ let columns = wrapper.findAll('th')
625
+ expect(columns.length).toBe(3)
626
+
627
+ // Simulate hiding a column by directly updating the headers
628
+ const updatedHeaders = [...headers] as TestDataTableHeader[]
629
+ updatedHeaders[1].hidden = true // Hide the Name column
630
+ organizeColumnsComponent.vm.$emit('update:headers', updatedHeaders)
631
+ await wrapper.vm.$nextTick()
632
+
633
+ // Check that the column is hidden
634
+ columns = wrapper.findAll('th')
635
+ expect(columns.length).toBe(2) // One less column should be visible
636
+ })
637
+
638
+ it('should move the column ID to the bottom', async () => {
639
+ // Import the sortHeaders function directly
640
+ const { sortHeaders } = await import('../../common/organizeColumns/sortHeaders')
641
+
642
+ // Add order property to headers for proper sorting
643
+ const headersWithOrder = headers.map((header, index) => ({
644
+ ...header,
645
+ order: index + 1,
646
+ }))
647
+
648
+ // Verify initial order after sorting
649
+ let sortedHeaders = sortHeaders([...headersWithOrder])
650
+ expect(sortedHeaders.length).toBe(3)
651
+ expect(sortedHeaders[0].title).toBe('ID')
652
+ expect(sortedHeaders[1].title).toBe('Name')
653
+ expect(sortedHeaders[2].title).toBe('Age')
654
+
655
+ // Update the headers to move ID to the bottom
656
+ const updatedHeaders = [
657
+ { ...headersWithOrder[0], order: 3 }, // ID moves to position 3
658
+ { ...headersWithOrder[1], order: 1 }, // Name stays at position 1
659
+ { ...headersWithOrder[2], order: 2 }, // Age moves to position 2
660
+ ]
661
+
662
+ // Check that the columns are in the correct order after sorting
663
+ sortedHeaders = sortHeaders(updatedHeaders)
664
+ expect(sortedHeaders.length).toBe(3)
665
+ expect(sortedHeaders[0].title).toBe('Name')
666
+ expect(sortedHeaders[1].title).toBe('Age')
667
+ expect(sortedHeaders[2].title).toBe('ID')
668
+ })
669
+
670
+ it('should move the column age to the top', async () => {
671
+ // Import the sortHeaders function directly
672
+ const { sortHeaders } = await import('../../common/organizeColumns/sortHeaders')
673
+
674
+ // Add order property to headers for proper sorting
675
+ const headersWithOrder = headers.map((header, index) => ({
676
+ ...header,
677
+ order: index + 1,
678
+ }))
679
+
680
+ // Verify initial order after sorting
681
+ let sortedHeaders = sortHeaders([...headersWithOrder])
682
+ expect(sortedHeaders.length).toBe(3)
683
+ expect(sortedHeaders[0].title).toBe('ID')
684
+ expect(sortedHeaders[1].title).toBe('Name')
685
+ expect(sortedHeaders[2].title).toBe('Age')
686
+
687
+ // Update the headers to move Age to the top
688
+ const updatedHeaders = [
689
+ { ...headersWithOrder[0], order: 2 }, // ID moves to position 2
690
+ { ...headersWithOrder[1], order: 3 }, // Name moves to position 3
691
+ { ...headersWithOrder[2], order: 1 }, // Age moves to position 1
692
+ ]
693
+
694
+ // Check that the columns are in the correct order after sorting
695
+ sortedHeaders = sortHeaders(updatedHeaders)
696
+ expect(sortedHeaders.length).toBe(3)
697
+ expect(sortedHeaders[0].title).toBe('Age')
698
+ expect(sortedHeaders[1].title).toBe('ID')
699
+ expect(sortedHeaders[2].title).toBe('Name')
700
+ })
701
+ })
450
702
  })