@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
@@ -0,0 +1,269 @@
1
+ <script setup lang="ts">
2
+ import { mdiEye, mdiEyeOff, mdiChevronUp, mdiChevronDown, mdiTableEdit } from '@mdi/js'
3
+ import { computed, ref, useId } from 'vue'
4
+ import { locales } from '../locales'
5
+ import { watch } from 'vue'
6
+ import type { DataTableHeaders } from '../types'
7
+ import { sortHeaders } from './sortHeaders'
8
+
9
+ const headers = defineModel<DataTableHeaders[]>(
10
+ 'headers',
11
+ {
12
+ required: true,
13
+ },
14
+ )
15
+
16
+ const items = ref<HTMLElement[] | null>(null)
17
+
18
+ // Ensure that all headers have an order defined
19
+ watch(
20
+ headers,
21
+ () => {
22
+ if (headers.value.find(header => header.order === undefined)) {
23
+ headers.value.forEach((header, index) => {
24
+ if (header.order === undefined) {
25
+ header.order = index + 1
26
+ }
27
+ })
28
+ }
29
+ },
30
+ { immediate: true, deep: true },
31
+ )
32
+
33
+ const visibleColumnsCount = computed(() => {
34
+ return headers.value.reduce(
35
+ (acc, header) => acc + (header.hidden ? 0 : 1),
36
+ 0,
37
+ ) || 0
38
+ })
39
+
40
+ let waitTransition = false
41
+ let appearItemId = ref<number>()
42
+ function right(header: DataTableHeaders) {
43
+ if (waitTransition) {
44
+ return
45
+ }
46
+ waitTransition = true
47
+ const newHeaders = JSON.parse(JSON.stringify(headers.value)) as DataTableHeaders[]
48
+ const nextHeader = newHeaders.find(h => h.order === header.order! + 1)
49
+ const currentHeader = newHeaders.find(h => h.order === header.order!)
50
+
51
+ const nextHeaderElement = items.value?.find(el => el['$attrs']['data-id'] === nextHeader!.key)
52
+ nextHeaderElement!['$el'].classList.add('fade-out')
53
+
54
+ const currentHeaderElement = items.value?.find(el => el['$attrs']['data-id'] === currentHeader!.key)
55
+ currentHeaderElement!['$el'].classList.add('to-bottom')
56
+
57
+ setTimeout(() => {
58
+ if (nextHeader) {
59
+ nextHeader.order = header.order
60
+ }
61
+ if (currentHeader) {
62
+ currentHeader.order = header.order! + 1
63
+ }
64
+ appearItemId.value = nextHeader!.order
65
+ headers.value = newHeaders
66
+
67
+ setTimeout(() => {
68
+ appearItemId.value = undefined
69
+ waitTransition = false
70
+ }, 200)
71
+ }, 300)
72
+ }
73
+
74
+ function left(header: DataTableHeaders) {
75
+ if (waitTransition) {
76
+ return
77
+ }
78
+ waitTransition = true
79
+ const newHeaders = JSON.parse(JSON.stringify(headers.value)) as DataTableHeaders[]
80
+ const previousHeader = newHeaders.find(h => h.order === header.order! - 1)
81
+ const currentHeader = newHeaders.find(h => h.order === header.order!)
82
+
83
+ const previousHeaderElement = items.value?.find(el => el['$attrs']['data-id'] === previousHeader!.key)
84
+ previousHeaderElement!['$el'].classList.add('fade-out')
85
+
86
+ const currentHeaderElement = items.value?.find(el => el['$attrs']['data-id'] === currentHeader!.key)
87
+ currentHeaderElement!['$el'].classList.add('to-top')
88
+
89
+ // update the order of the previous header
90
+ setTimeout(() => {
91
+ if (previousHeader) {
92
+ previousHeader.order = header.order
93
+ }
94
+ if (currentHeader) {
95
+ currentHeader.order = header.order! - 1
96
+ }
97
+ appearItemId.value = previousHeader!.order
98
+ headers.value = newHeaders
99
+
100
+ setTimeout(() => {
101
+ appearItemId.value = undefined
102
+ waitTransition = false
103
+ }, 200)
104
+ }, 300)
105
+ }
106
+ const orderedHeaders = ref<DataTableHeaders[]>([])
107
+ watch(
108
+ headers,
109
+ () => {
110
+ orderedHeaders.value = sortHeaders(headers.value)
111
+ },
112
+ { immediate: true, deep: true },
113
+ )
114
+
115
+ // Generate unique IDs for components using the useId composable
116
+ const columnsMenuId = useId() + '-organize-columns-menu'
117
+ const columnsTitleId = useId() + '-organize-columns-title'
118
+
119
+ // Track menu open state
120
+ const isMenuOpen = ref(false)
121
+
122
+ // Generate unique IDs for header items
123
+ const getHeaderId = (title: string) => {
124
+ return useId() + `-header-${title}`
125
+ }
126
+
127
+ </script>
128
+
129
+ <template>
130
+ <div
131
+ v-if="headers && headers.length > 0"
132
+ class="ml-3"
133
+ >
134
+ <VMenu
135
+ :id="columnsMenuId"
136
+ v-model="isMenuOpen"
137
+ :close-on-content-click="false"
138
+ location="end"
139
+ attach="body"
140
+ >
141
+ <template #activator="{ props }">
142
+ <VBtn
143
+ :title="locales.reorganizeColumns"
144
+ variant="outlined"
145
+ color="primary"
146
+ v-bind="props"
147
+ aria-haspopup="menu"
148
+ :aria-controls="isMenuOpen ? columnsMenuId : undefined"
149
+ >
150
+ <VIcon size="large">
151
+ {{ mdiTableEdit }}
152
+ </VIcon>
153
+ </VBtn>
154
+ </template>
155
+ <VCard min-width="300">
156
+ <VCardTitle :id="columnsTitleId">
157
+ {{ locales.reorganizeColumnsTitle }}
158
+ </VCardTitle>
159
+ <VList
160
+ :aria-labelledby="columnsTitleId"
161
+ >
162
+ <VListItem
163
+ v-for="(header, index) in orderedHeaders"
164
+ ref="items"
165
+ :key="`${header!.key!}${index}`"
166
+ :data-id="header!.key"
167
+ :class="{
168
+ 'fade-in': appearItemId === header.order,
169
+ }"
170
+ >
171
+ <div class="d-flex ga-8 justify-space-between align-center w-100">
172
+ <div class="d-flex align-center flex-row-reverse">
173
+ <div :id="getHeaderId(header!.title as string)">
174
+ {{ header!.title }}
175
+ </div>
176
+ <VBtn
177
+ :title="header.hidden ? locales.showColumn(header.title as string) : locales.hideColumn(header.title as string)"
178
+ elevation="0"
179
+ variant="text"
180
+ color="primary"
181
+ width="45"
182
+ min-width="45"
183
+ class="mr-2"
184
+ :disabled="visibleColumnsCount <= 1 && !header.hidden"
185
+ @click="() => {
186
+ header.hidden = !header.hidden
187
+ }"
188
+ >
189
+ <VIcon>
190
+ {{ header.hidden ? mdiEyeOff : mdiEye }}
191
+ </VIcon>
192
+ </VBtn>
193
+ </div>
194
+ <div class="d-flex ga-2 pa-2">
195
+ <VBtnGroup
196
+ variant="text"
197
+ tile
198
+ active-color="primary"
199
+ slim
200
+ density="compact"
201
+ >
202
+ <VBtn
203
+ :title="locales.moveColumnLeft(header.title as string)"
204
+ :disabled="index === 0"
205
+ width="45"
206
+ min-width="45"
207
+ color="primary"
208
+ @click="left(header)"
209
+ >
210
+ <VIcon
211
+ size="x-large"
212
+ >
213
+ {{ mdiChevronUp }}
214
+ </VIcon>
215
+ </VBtn>
216
+ <VBtn
217
+ :title="locales.moveColumnRight(header.title as string)"
218
+ :disabled="index === headers!.length - 1"
219
+ width="45"
220
+ min-width="45"
221
+ color="primary"
222
+ @click="right(header)"
223
+ >
224
+ <VIcon
225
+ size="x-large"
226
+ >
227
+ {{ mdiChevronDown }}
228
+ </VIcon>
229
+ </VBtn>
230
+ </VBtnGroup>
231
+ </div>
232
+ </div>
233
+ </VListItem>
234
+ </VList>
235
+ </VCard>
236
+ </VMenu>
237
+ </div>
238
+ </template>
239
+
240
+ <style lang="scss" scoped>
241
+ .fade-out {
242
+ opacity: 0;
243
+ transition: opacity 0.2s ease-out;
244
+ }
245
+
246
+ .fade-in {
247
+ animation: fade-in 0.2s ease-out forwards;
248
+ }
249
+
250
+ .to-top {
251
+ transition: transform 0.2s 0.1s ease-out;
252
+ transform: translateY(-100%);
253
+ }
254
+
255
+ .to-bottom {
256
+ transition: transform 0.2s 0.1s ease-out;
257
+ transform: translateY(100%);
258
+ }
259
+
260
+ @keyframes fade-in {
261
+ 0% {
262
+ opacity: 0;
263
+ }
264
+
265
+ 100% {
266
+ opacity: 1;
267
+ }
268
+ }
269
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { DataTableHeaders } from '../types'
2
+
3
+ export function sortHeaders(
4
+ headers: DataTableHeaders[],
5
+ ): DataTableHeaders[] {
6
+ return [...headers].sort((a, b) => {
7
+ return (a.order || 0) - (b.order || 0)
8
+ })
9
+ }
@@ -1,327 +1,75 @@
1
1
  import type { FilterOption } from './types'
2
-
3
- function parseDate(value: unknown): Date | null {
4
- if (value instanceof Date) return value
5
- if (typeof value === 'string') {
6
- try {
7
- if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(value)) {
8
- const [day, month, year] = value.split('/').map(Number)
9
- return new Date(year, month - 1, day)
10
- }
11
- const parsed = new Date(value)
12
- return isNaN(parsed.getTime()) ? null : parsed
13
- }
14
- catch {
15
- return null
16
- }
17
- }
18
- // Traite le type nombre
19
- if (typeof value === 'number') {
20
- const parsed = new Date(value)
21
- return isNaN(parsed.getTime()) ? null : parsed
22
- }
23
- // Ignore les objets vides
24
- if (value === null || value === undefined || (typeof value === 'object' && Object.keys(value as object).length === 0)) {
25
- return null
26
- }
27
- return null
28
- }
2
+ import filterByPeriod from './filters/logics/period'
3
+ import filterByExactDate from './filters/logics/date'
4
+ import filterByNumber from './filters/logics/number'
5
+ import filterBySelect from './filters/logics/select'
6
+ import filterByText from './filters/logics/text'
29
7
 
30
8
  export function filterItems<T extends Record<string, unknown>>(items: T[], filters: FilterOption[]): T[] {
31
9
  if (!Array.isArray(items) || items.length === 0) return []
32
10
  if (!Array.isArray(filters) || filters.length === 0) return items
33
11
 
34
- // Traitement spécial pour les tests de TextFilter
35
- if (filters.length === 1 && filters[0].key === 'text') {
36
- const filterValue = String(filters[0].value)
37
-
38
- // Cas spécifiques pour les tests TextFilter.spec.ts
39
- if (filterValue === 'cherry') {
40
- return items.filter(item => item.text === 'Cherry')
41
- }
42
-
43
- if (filterValue === '"Cherry"') {
44
- return items.filter(item => item.text === 'Cherry')
45
- }
46
-
47
- if (filterValue === '"cherry"') {
48
- // Cas spécifique pour le test de recherche sensible à la casse (ne doit rien retourner)
49
- return [] // Doit retourner un tableau vide car aucun élément ne correspond exactement
50
- }
51
-
52
- if (filterValue === 'a*') {
53
- return items.filter(item => ['apple', 'banana'].includes(String(item.text)))
54
- }
55
-
56
- if (filterValue === '????') {
57
- return items.filter(item => ['apple', 'date', 'fig'].includes(String(item.text)))
58
- }
59
-
60
- if (filterValue === '=????') {
61
- return items.filter(item => ['apple', 'date', 'fig'].includes(String(item.text)))
62
- }
63
-
64
- if (filterValue === '=?????') {
65
- // Cas spécifique pour le test de longueur exacte avec 5 caractères
66
- // Le test attend spécifiquement les items avec ID 2 (banana) et 5 (Elderberry)
67
- return items.filter(item => [2, 5].includes(Number(item.id)))
68
- }
69
-
70
- if (filterValue === 'e*') {
71
- return items.filter(item => item.text === 'Elderberry')
72
- }
73
-
74
- if (filterValue === '*r*') {
75
- return items.filter(item => ['Cherry', 'Elderberry', 'grape'].includes(String(item.text)))
76
- }
77
-
78
- if (filterValue === '>f') {
79
- return items.filter(item => ['fig', 'grape'].includes(String(item.text)))
80
- }
81
- }
82
-
83
- // Traitement spécial pour le test tableFilterUtils.spec.ts > should handle partial matches for text filters
84
- if (filters.length === 1 && filters[0].key === 'name' && filters[0].value === 'oh') {
85
- return items.filter(item => ['John Doe', 'Bob Johnson'].includes(String(item.name)))
86
- }
87
-
88
12
  return items.filter((item) => {
89
13
  return filters.every(filter => applyFilter(item, filter))
90
14
  })
91
15
  }
92
16
 
93
- /**
94
- * Convertit une chaîne de caractères de filtre avec des caractères spéciaux en expression régulière
95
- * @param filterStr Chaîne de caractères de filtre
96
- * @returns Expression régulière correspondante
97
- */
98
- function convertFilterToRegex(filterStr: string): { regex: RegExp, caseSensitive: boolean, isGreaterThan?: boolean } {
99
- // Cas spécial pour la recherche sensible à la casse (entre guillemets doubles)
100
- const caseSensitiveMatch = /^"(.+)"$/.exec(filterStr)
101
- if (caseSensitiveMatch) {
102
- // Recherche sensible à la casse - exacte pour les tests
103
- const exactPattern = `^${caseSensitiveMatch[1]}$`
104
- return { regex: new RegExp(exactPattern), caseSensitive: true }
105
- }
106
-
107
- // Traiter les cas spéciaux
108
- // Cas <>?* - Toutes les valeurs vides ou nulles
109
- if (filterStr === '<>?*') {
110
- return { regex: /^\s*$/, caseSensitive: false }
111
- }
112
-
113
- // Cas =???? - Tous les mots de 4 lettres exactement (ou autre longueur)
114
- const exactLengthMatch = /^=(\?+)$/.exec(filterStr)
115
- if (exactLengthMatch) {
116
- const length = exactLengthMatch[1].length
117
- return { regex: new RegExp(`^.{${length}}$`), caseSensitive: false }
118
- }
119
-
120
- // Cas >zu - Tous les mots classés après "zu" alphabétiquement
121
- const greaterThanMatch = /^>(.+)$/.exec(filterStr)
122
- if (greaterThanMatch) {
123
- // On ne peut pas utiliser une regex pour cette comparaison, on utilisera une fonction spéciale
124
- return { regex: new RegExp(`.`), caseSensitive: false, isGreaterThan: true }
125
- }
126
-
127
- // Pour les recherches avec wildcards, traiter spécialement selon les tests
128
- if (filterStr === 'a*') {
129
- // Cas spécifique pour le test 'a*' qui doit retourner apple et banana
130
- return { regex: new RegExp(`^a`), caseSensitive: false }
131
- }
132
-
133
- if (filterStr === '????') {
134
- // Cas spécifique pour le test '????' qui doit retourner des mots de 4 lettres
135
- return { regex: new RegExp(`^.{4}$`), caseSensitive: false }
136
- }
137
-
138
- if (filterStr === 'e*') {
139
- // Cas spécifique pour le test 'e*' qui doit retourner Elderberry uniquement
140
- return { regex: new RegExp(`^e`, 'i'), caseSensitive: false }
141
- }
142
-
143
- if (filterStr === '*r*') {
144
- // Cas spécifique pour le test '*r*' qui doit retourner Cherry, Elderberry et grape
145
- return { regex: new RegExp(`r`, 'i'), caseSensitive: false }
146
- }
147
-
148
- // Recherche insensible à la casse par défaut avec correspondance partielle
149
- return { regex: new RegExp(filterStr, 'i'), caseSensitive: false }
150
- }
151
-
152
17
  function applyFilter<T extends Record<string, unknown>>(item: T, filter: FilterOption): boolean {
153
18
  if (!filter.key) return true
154
19
 
155
20
  const itemValue = item[filter.key]
156
21
  const filterValue = filter.value
157
22
 
158
- if (itemValue == null || filterValue == null) return true
23
+ if (filterValue == null) return true
159
24
 
160
25
  switch (filter.type) {
161
26
  case 'text': {
162
- const str = String(itemValue)
163
- const search = String(filterValue)
164
-
165
- // Traitement spécial pour certains cas de test
166
- if (search === 'cherry') {
167
- // Cas spécifique pour le test de recherche insensible à la casse
168
- return str.toLowerCase() === 'cherry'
169
- }
170
-
171
- if (search === '"Cherry"') {
172
- // Cas spécifique pour le test de recherche sensible à la casse
173
- return str === 'Cherry'
174
- }
175
-
176
- if (search === '>f') {
177
- // Cas spécifique pour le test de comparaison alphabétique
178
- return ['fig', 'grape'].includes(str)
179
- }
180
-
181
- if (search === 'a*') {
182
- // Cas spécifique pour le test de wildcard *
183
- return ['apple', 'banana'].includes(str)
184
- }
185
-
186
- if (search === '????') {
187
- // Cas spécifique pour le test de wildcard ?
188
- return ['apple', 'date', 'fig'].includes(str)
189
- }
190
-
191
- if (search === '=????') {
192
- // Cas spécifique pour le test de longueur exacte
193
- return ['apple', 'date', 'fig'].includes(str)
194
- }
195
-
196
- if (search === 'e*') {
197
- // Cas spécifique pour le test de préfixe
198
- return str === 'Elderberry'
199
- }
200
-
201
- if (search === '*r*') {
202
- // Cas spécifique pour le test de wildcards multiples
203
- return ['Cherry', 'Elderberry', 'grape'].includes(str)
204
- }
205
-
206
- // Cas spécial pour les valeurs vides ou nulles
207
- if (search === '<>?*') {
208
- return str.trim() === ''
209
- }
210
-
211
- // Utiliser la fonction de conversion en regex pour les autres cas
212
- const result = convertFilterToRegex(search)
213
-
214
- if (result.caseSensitive) {
215
- return result.regex.test(str)
216
- }
217
- else {
218
- return result.regex.test(str.toLowerCase())
219
- }
27
+ return filterByText(itemValue, filterValue)
220
28
  }
221
29
  case 'number': {
222
- if (typeof itemValue === 'number') {
223
- // Handle string filter values that may contain operators
224
- if (typeof filterValue === 'string') {
225
- // Check for operators at the beginning of the string
226
- const operatorMatch = /^([=<>]{1,2})(.+)$/.exec(filterValue)
227
- if (operatorMatch) {
228
- const operator = operatorMatch[1]
229
- const valueStr = operatorMatch[2].trim()
230
- const numValue = parseFloat(valueStr.replace(',', '.'))
231
-
232
- if (isNaN(numValue)) return false
233
-
234
- switch (operator) {
235
- case '=':
236
- return itemValue === numValue
237
- case '<>':
238
- return itemValue !== numValue
239
- case '<':
240
- return itemValue < numValue
241
- case '<=':
242
- return itemValue <= numValue
243
- case '>':
244
- return itemValue > numValue
245
- case '>=':
246
- return itemValue >= numValue
247
- default:
248
- return false
249
- }
250
- }
251
-
252
- // No operator, try to parse the value and do exact match
253
- const numValue = parseFloat(filterValue.replace(',', '.'))
254
- if (!isNaN(numValue)) {
255
- return itemValue === numValue
256
- }
257
- return false
258
- }
259
-
260
- // Handle numeric filter values (exact match)
261
- if (typeof filterValue === 'number') {
262
- return itemValue === filterValue
263
- }
264
-
265
- return String(itemValue).includes(String(filterValue))
266
- }
267
- return false
30
+ return filterByNumber(itemValue, filterValue)
268
31
  }
269
32
  case 'select': {
270
- if (Array.isArray(filterValue)) {
271
- // Utilise l'assertion de type pour gérer la méthode includes
272
- return filterValue.includes(itemValue as unknown as typeof filterValue[0])
273
- }
274
- if (typeof filterValue === 'object' && filterValue != null) {
275
- return JSON.stringify(filterValue) === JSON.stringify(itemValue)
276
- }
277
- return itemValue === filterValue
33
+ return filterBySelect(itemValue, filterValue)
278
34
  }
279
- case 'period': {
280
- if (
281
- typeof itemValue === 'object'
282
- && itemValue !== null
283
- && 'from' in itemValue
284
- && 'to' in itemValue
285
- ) {
286
- const { from, to } = filterValue as { from?: string | Date, to?: string | Date }
287
-
288
- if (!from || !to) {
289
- return true
290
- }
291
-
292
- const itemFrom = parseDate(itemValue.from)
293
- const itemTo = parseDate(itemValue.to)
294
- const fromDate = parseDate(from)
295
- const toDate = parseDate(to)
296
-
297
- if (!itemFrom || !itemTo || !fromDate || !toDate) {
298
- return false
299
- }
300
-
301
- const normalizeDate = (date: Date) =>
302
- new Date(date.getFullYear(), date.getMonth(), date.getDate())
303
-
304
- const itemFromDay = normalizeDate(itemFrom)
305
- const itemToDay = normalizeDate(itemTo)
306
- const fromDay = normalizeDate(fromDate)
307
- const toDay = normalizeDate(toDate)
308
-
309
- // Applique la vérification de chevauchement uniquement si les deux dates sont valides
310
- return itemFromDay <= toDay && itemToDay >= fromDay
311
- }
312
- return false
35
+ case 'custom': {
36
+ // Traiter les filtres personnalisés comme des filtres de sélection
37
+ return filterBySelect(itemValue, filterValue)
38
+ }
39
+ case 'period':{
40
+ return filterByPeriod(itemValue, filterValue)
313
41
  }
314
42
  case 'date': {
315
- const itemDate = parseDate(itemValue)
316
- const targetDate = parseDate(filterValue)
317
- if (!itemDate || !targetDate) return false
318
- return (
319
- itemDate.getDate() === targetDate.getDate()
320
- && itemDate.getMonth() === targetDate.getMonth()
321
- && itemDate.getFullYear() === targetDate.getFullYear()
322
- )
43
+ return filterByExactDate(itemValue, filterValue)
323
44
  }
324
45
  default:
325
46
  return true
326
47
  }
327
48
  }
49
+
50
+ export function parseDate(value: unknown): Date | null {
51
+ if (value instanceof Date) return value
52
+ if (typeof value === 'string') {
53
+ try {
54
+ if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(value)) {
55
+ const [day, month, year] = value.split('/').map(Number)
56
+ return new Date(year, month - 1, day)
57
+ }
58
+ const parsed = new Date(value)
59
+ return isNaN(parsed.getTime()) ? null : parsed
60
+ }
61
+ catch {
62
+ return null
63
+ }
64
+ }
65
+ // Traite le type nombre
66
+ if (typeof value === 'number') {
67
+ const parsed = new Date(value)
68
+ return isNaN(parsed.getTime()) ? null : parsed
69
+ }
70
+ // Ignore les objets vides
71
+ if (value === null || value === undefined || (typeof value === 'object' && Object.keys(value as object).length === 0)) {
72
+ return null
73
+ }
74
+ return null
75
+ }