@cnamts/synapse 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{DateFilter-BmRuzQ9Z.js → DateFilter-YWOTbfeL.js} +1 -1
- package/dist/{NumberFilter-CnIPDHqx.js → NumberFilter-DMmMgALM.js} +1 -1
- package/dist/{PeriodFilter-CZwZ8CnQ.js → PeriodFilter-Bok5BHcn.js} +1 -1
- package/dist/SelectFilter-BKud2WhN.js +136 -0
- package/dist/{TextFilter-DTxZHJwX.js → TextFilter-DvMf2thH.js} +1 -1
- package/dist/components/Accordion/Accordion.d.ts +2 -1
- package/dist/components/Accordion/composables/useAccordionGroupCommunication.d.ts +5 -0
- package/dist/components/Accordion/composables/useAccordionKeyboardNavigation.d.ts +12 -0
- package/dist/components/Accordion/composables/useAccordionState.d.ts +13 -0
- package/dist/components/Customs/SyCheckbox/SyCheckbox.d.ts +85 -0
- package/dist/components/Customs/SyInputSelect/SyInputSelect.d.ts +2 -0
- package/dist/components/Customs/SySelect/SySelect.d.ts +33 -13
- package/dist/components/Customs/SyTextField/SyTextField.d.ts +2 -2
- package/dist/components/DatePicker/ComplexDatePicker/ComplexDatePicker.d.ts +1585 -1452
- package/dist/components/DatePicker/DatePicker/DatePicker.d.ts +16 -2
- package/dist/components/DatePicker/DateTextInput/DateTextInput.d.ts +3 -1
- package/dist/components/DatePicker/composables/index.d.ts +2 -0
- package/dist/components/DatePicker/composables/useAsteriskDisplay.d.ts +14 -0
- package/dist/components/DatePicker/composables/useDateAutoClamp.d.ts +16 -0
- package/dist/components/DatePicker/composables/useDateRangeInput.d.ts +1 -1
- package/dist/components/DatePicker/composables/useDisplayedDateString.d.ts +3 -0
- package/dist/components/DatePicker/composables/useInputBlurHandler.d.ts +1 -0
- package/dist/components/DatePicker/composables/useMonthButtonCustomization.d.ts +5 -2
- package/dist/components/NirField/NirField.d.ts +7 -3
- package/dist/components/NirField/nirValidation.d.ts +1 -1
- package/dist/components/PasswordField/PasswordField.d.ts +2 -0
- package/dist/components/PeriodField/PeriodField.d.ts +52 -8
- package/dist/components/PhoneField/PhoneField.d.ts +2 -2
- package/dist/components/RangeField/RangeField.d.ts +2 -0
- package/dist/components/SearchListField/SearchListField.d.ts +9 -0
- package/dist/components/SyTextArea/SyTextArea.d.ts +2 -0
- package/dist/components/Tables/SyServerTable/SyServerTable.d.ts +14 -9
- package/dist/components/Tables/SyTable/SyTable.d.ts +12 -7
- package/dist/components/Tables/common/SyTablePagination.d.ts +1636 -0
- package/dist/components/Tables/common/TableHeader.d.ts +2 -20
- package/dist/components/Tables/common/filters/SelectFilter.d.ts +5 -5
- package/dist/components/Tables/common/filters/getFilterComponent.d.ts +1 -0
- package/dist/components/Tables/common/filters/locales.d.ts +4 -0
- package/dist/components/Tables/common/filters/logics/date.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/number.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/period.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/select.d.ts +1 -0
- package/dist/components/Tables/common/filters/logics/text.d.ts +1 -0
- package/dist/components/Tables/common/locales.d.ts +21 -0
- package/dist/components/Tables/common/organizeColumns/OrganizeColumns.d.ts +267 -0
- package/dist/components/Tables/common/organizeColumns/sortHeaders.d.ts +2 -0
- package/dist/components/Tables/common/tableFilterUtils.d.ts +1 -0
- package/dist/components/Tables/common/tableStorageUtils.d.ts +41 -1
- package/dist/components/Tables/common/tableUtils.d.ts +42 -5
- package/dist/components/Tables/common/types.d.ts +19 -8
- package/dist/components/Tables/common/usePagination.d.ts +22 -0
- package/dist/components/Tables/common/useTableCheckbox.d.ts +20 -0
- package/dist/components/Tables/common/useTableHeaders.d.ts +76 -0
- package/dist/components/Tables/common/useTableItems.d.ts +24 -0
- package/dist/components/Tables/common/useTableOptions.d.ts +18 -0
- package/dist/components/ToolbarContainer/ToolbarContainer.d.ts +11 -0
- package/dist/components/UserMenuBtn/UserMenuBtn.d.ts +9 -2
- package/dist/components/index.d.ts +8 -6
- package/dist/design-system-v3.js +58 -56
- package/dist/design-system-v3.umd.cjs +22 -22
- package/dist/main-Cx8qG7YR.js +16344 -0
- package/dist/stories/Accessibilite/Vuetify/VuetifyItems.d.ts +14 -2
- package/dist/stories/DesignTokens/StylesTypographiques.stories.new.d.ts +8 -0
- package/dist/stories/DesignTokens/TypographyDisplay.d.ts +28 -0
- package/dist/stories/DesignTokens/vue-shims.d.ts +6 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/common/imgs/accessibility-svgrepo-com.svg +4 -0
- package/src/components/Accordion/Accessibilite/AccessibilityGuide.mdx +249 -0
- package/src/components/Accordion/Accordion.vue +48 -76
- package/src/components/Accordion/composables/__tests__/useAccordionGroupCommunication.spec.ts +146 -0
- package/src/components/Accordion/composables/__tests__/useAccordionKeyboardNavigation.spec.ts +209 -0
- package/src/components/Accordion/composables/__tests__/useAccordionState.spec.ts +144 -0
- package/src/components/Accordion/composables/useAccordionGroupCommunication.ts +52 -0
- package/src/components/Accordion/composables/useAccordionKeyboardNavigation.ts +111 -0
- package/src/components/Accordion/composables/useAccordionState.ts +59 -0
- package/src/components/Accordion/tests/__snapshots__/accordion.spec.ts.snap +3 -0
- package/src/components/Customs/SyCheckbox/Accessibilite.mdx +303 -0
- package/src/components/Customs/SyCheckbox/SyCheckbox.mdx +50 -0
- package/src/components/Customs/SyCheckbox/SyCheckbox.stories.ts +630 -0
- package/src/components/Customs/SyCheckbox/SyCheckbox.vue +326 -0
- package/src/components/Customs/SyCheckbox/tests/SyCheckbox.spec.ts +201 -0
- package/src/components/Customs/SyInputSelect/SyInputSelect.stories.ts +1 -0
- package/src/components/Customs/SyInputSelect/SyInputSelect.vue +8 -1
- package/src/components/Customs/SySelect/SySelect.stories.ts +160 -0
- package/src/components/Customs/SySelect/SySelect.vue +291 -32
- package/src/components/Customs/SySelect/tests/SySelect.spec.ts +230 -0
- package/src/components/Customs/SyTextField/SyTextField.stories.ts +3 -2
- package/src/components/Customs/SyTextField/SyTextField.vue +19 -8
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.stories.ts +241 -31
- package/src/components/DatePicker/ComplexDatePicker/ComplexDatePicker.vue +305 -57
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.events.spec.ts +161 -0
- package/src/components/DatePicker/ComplexDatePicker/tests/ComplexDatePicker.spec.ts +4 -2
- package/src/components/DatePicker/DatePicker/DatePicker.stories.ts +259 -137
- package/src/components/DatePicker/DatePicker/DatePicker.vue +153 -25
- package/src/components/DatePicker/DatePicker/tests/DatePicker.events.spec.ts +189 -0
- package/src/components/DatePicker/DatePicker/{DatePicker.spec.ts → tests/DatePicker.spec.ts} +1 -15
- package/src/components/DatePicker/DateTextInput/DateRange.stories.ts +24 -14
- package/src/components/DatePicker/DateTextInput/DateTextInput.events.spec.ts +148 -0
- package/src/components/DatePicker/DateTextInput/DateTextInput.spec.ts +3 -1
- package/src/components/DatePicker/DateTextInput/DateTextInput.vue +200 -5
- package/src/components/DatePicker/DateTextInput/NoCalendar.stories.ts +241 -31
- package/src/components/DatePicker/composables/index.ts +2 -0
- package/src/components/DatePicker/composables/tests/useDateAutoClamp.spec.ts +190 -0
- package/src/components/DatePicker/composables/tests/useInputBlurHandler.spec.ts +182 -4
- package/src/components/DatePicker/composables/tests/useMonthButtonCustomization.spec.ts +105 -80
- package/src/components/DatePicker/composables/useAsteriskDisplay.ts +31 -0
- package/src/components/DatePicker/composables/useDateAutoClamp.ts +136 -0
- package/src/components/DatePicker/composables/useDateRangeInput.ts +21 -18
- package/src/components/DatePicker/composables/useDisplayedDateString.ts +13 -1
- package/src/components/DatePicker/composables/useInputBlurHandler.ts +84 -20
- package/src/components/DatePicker/composables/useMonthButtonCustomization.ts +149 -51
- package/src/components/DiacriticPicker/DiacriticPicker.stories.ts +10 -0
- package/src/components/ErrorPage/Accessibilite.stories.ts +8 -0
- package/src/components/ErrorPage/ErrorPage.vue +12 -6
- package/src/components/ErrorPage/tests/__snapshots__/ErrorPage.spec.ts.snap +4 -4
- package/src/components/NirField/NirField.mdx +22 -9
- package/src/components/NirField/NirField.stories.ts +26 -2
- package/src/components/NirField/NirField.vue +209 -22
- package/src/components/NirField/nirValidation.ts +17 -3
- package/src/components/NirField/tests/NirField.spec.ts +2 -2
- package/src/components/NotFoundPage/Accessibilite.stories.ts +8 -0
- package/src/components/NotFoundPage/NotFoundPage.vue +2 -1
- package/src/components/NotFoundPage/tests/__snapshots__/NotFoundPage.spec.ts.snap +8 -6
- package/src/components/PaginatedTable/PaginatedTable.mdx +2 -0
- package/src/components/PasswordField/PasswordField.stories.ts +4 -0
- package/src/components/PasswordField/PasswordField.vue +3 -0
- package/src/components/PeriodField/PeriodField.vue +2 -0
- package/src/components/PhoneField/PhoneField.stories.ts +15 -15
- package/src/components/PhoneField/PhoneField.vue +1 -1
- package/src/components/RangeField/RangeField.stories.ts +9 -0
- package/src/components/RangeField/RangeField.vue +4 -0
- package/src/components/RangeField/tests/__snapshots__/RangeField.spec.ts.snap +12 -0
- package/src/components/SearchListField/SearchListField.vue +5 -0
- package/src/components/SyTextArea/SyTextArea.vue +3 -0
- package/src/components/SyTextArea/tests/SyTextArea.spec.ts +0 -1
- package/src/components/Tables/SyServerTable/FilterRules.stories.ts +632 -15
- package/src/components/Tables/SyServerTable/SyServerTable.mdx +15 -5
- package/src/components/Tables/SyServerTable/SyServerTable.stories.ts +2844 -1377
- package/src/components/Tables/SyServerTable/SyServerTable.vue +155 -66
- package/src/components/Tables/SyServerTable/tests/SyServerTable.spec.ts +256 -4
- package/src/components/Tables/SyTable/FilterRules.stories.ts +183 -0
- package/src/components/Tables/SyTable/SyTable.mdx +14 -4
- package/src/components/Tables/SyTable/SyTable.stories.ts +1265 -477
- package/src/components/Tables/SyTable/SyTable.vue +152 -72
- package/src/components/Tables/SyTable/tests/SyTable.spec.ts +366 -4
- package/src/components/Tables/common/SyTableFilter.vue +3 -56
- package/src/components/Tables/common/SyTablePagination.vue +375 -0
- package/src/components/Tables/common/TableHeader.vue +10 -26
- package/src/components/Tables/common/filters/SelectFilter.vue +131 -22
- package/src/components/Tables/common/filters/getFilterComponent.ts +54 -0
- package/src/components/Tables/common/filters/locales.ts +4 -0
- package/src/components/Tables/common/filters/logics/date.ts +12 -0
- package/src/components/Tables/common/filters/logics/number.ts +48 -0
- package/src/components/Tables/common/filters/logics/period.ts +25 -0
- package/src/components/Tables/common/filters/logics/select.ts +27 -0
- package/src/components/Tables/common/filters/logics/tests/TextFilterLogic.spec.ts +177 -0
- package/src/components/Tables/common/filters/logics/text.ts +62 -0
- package/src/components/Tables/common/filters/tests/TextFilter.spec.ts +11 -11
- package/src/components/Tables/common/locales.ts +24 -0
- package/src/components/Tables/common/organizeColumns/OrganizeColumns.vue +269 -0
- package/src/components/Tables/common/organizeColumns/sortHeaders.ts +9 -0
- package/src/components/Tables/common/tableFilterUtils.ts +43 -295
- package/src/components/Tables/common/tableStorageUtils.ts +27 -2
- package/src/components/Tables/common/tableStyles.scss +26 -0
- package/src/components/Tables/common/tableUtils.ts +3 -16
- package/src/components/Tables/common/tests/SyTablePagination.spec.ts +170 -0
- package/src/components/Tables/common/tests/filterByRange.spec.ts +215 -0
- package/src/components/Tables/common/tests/tableFilterUtils.spec.ts +0 -14
- package/src/components/Tables/common/tests/tableUtils.spec.ts +7 -51
- package/src/components/Tables/common/types.ts +17 -6
- package/src/components/Tables/common/usePagination.ts +83 -0
- package/src/components/Tables/common/useTableCheckbox.ts +58 -0
- package/src/components/Tables/common/useTableHeaders.ts +88 -0
- package/src/components/Tables/common/useTableItems.ts +87 -0
- package/src/components/Tables/common/useTableOptions.ts +93 -0
- package/src/components/ToolbarContainer/ToolbarContainer.mdx +16 -0
- package/src/components/ToolbarContainer/ToolbarContainer.stories.ts +675 -0
- package/src/components/ToolbarContainer/ToolbarContainer.vue +128 -0
- package/src/components/ToolbarContainer/tests/ToolbarContainer.spec.ts +156 -0
- package/src/components/UserMenuBtn/UserMenuBtn.stories.ts +74 -0
- package/src/components/UserMenuBtn/UserMenuBtn.vue +19 -17
- package/src/components/index.ts +8 -6
- package/src/stories/Accessibilite/Aculturation/AuditDesignSystem.mdx +293 -20
- package/src/stories/Accessibilite/Aculturation/SensibilisationAccessibilite.mdx +448 -54
- package/src/stories/Accessibilite/Audit/RGAA.mdx +231 -23
- package/src/stories/Accessibilite/Avancement/Avancement.mdx +591 -7
- package/src/stories/Accessibilite/Avancement/Avancement.stories.ts +139 -38
- package/src/stories/Accessibilite/Introduction.mdx +258 -18
- package/src/stories/Accessibilite/KitDePreAudit/Echantillonnage.mdx +221 -31
- package/src/stories/Accessibilite/KitDePreAudit/Introduction.mdx +204 -22
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Introduction.mdx +537 -24
- package/src/stories/Accessibilite/KitDePreAudit/Outils/LecteursDEcran.mdx +577 -70
- package/src/stories/Accessibilite/KitDePreAudit/Outils/Tanaguru.mdx +382 -31
- package/src/stories/Accessibilite/KitDePreAudit/Preaudit.mdx +419 -81
- package/src/stories/Accessibilite/Vuetify/Vuetify.mdx +132 -6
- package/src/stories/Accessibilite/Vuetify/Vuetify.stories.ts +370 -146
- package/src/stories/Accessibilite/Vuetify/VuetifyItems.ts +35 -57
- package/src/stories/Demarrer/Accueil.stories.ts +20 -5
- package/src/stories/DesignTokens/StylesTypographiques.mdx +10 -9
- package/src/stories/DesignTokens/StylesTypographiques.stories.new.ts +397 -0
- package/src/stories/DesignTokens/StylesTypographiques.stories.ts +397 -0
- package/src/stories/DesignTokens/TypographyDisplay.vue +155 -0
- package/src/stories/DesignTokens/vue-shims.d.ts +6 -0
- package/src/stories/GuideDuDev/LesBreackingChanges.mdx +0 -2
- package/src/stories/GuideDuDev/MigrationDepuisBridge.mdx +1 -1
- package/src/stories/GuideDuDev/MigrationDepuisVue2.mdx +1 -1
- package/src/stories/GuideDuDev/PortailAgent.mdx +10 -0
- package/src/stories/GuideDuDev/PortailAgent.stories.ts +506 -0
- package/src/stories/GuideDuDev/Theme.mdx +41 -0
- package/dist/SelectFilter-Cj-GW2Cc.js +0 -97
- package/dist/main-WDqeoGM-.js +0 -14788
- package/src/components/PaginatedTable/tests/__snapshots__/PaginatedTable.spec.ts.snap +0 -886
- package/src/components/Tables/SyServerTable/tests/__snapshots__/SyServerTable.spec.ts.snap +0 -521
- package/src/components/Tables/SyTable/tests/__snapshots__/SyTable.spec.ts.snap +0 -521
- package/src/stories/DesignTokens/ThemePA.mdx +0 -35
|
@@ -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>
|
|
@@ -1,327 +1,75 @@
|
|
|
1
1
|
import type { FilterOption } from './types'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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 (
|
|
23
|
+
if (filterValue == null) return true
|
|
159
24
|
|
|
160
25
|
switch (filter.type) {
|
|
161
26
|
case 'text': {
|
|
162
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 '
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
|
|
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
|
+
}
|