@citizenplane/pimp 8.26.1 → 8.28.1

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 (187) hide show
  1. package/dist/{IconAccompaniedMinorEach-CUq3oXbX.js → IconAccompaniedMinorEach-MkIJAypb.js} +1 -1
  2. package/dist/{IconAccompaniedMinorNone-nZ4eSfTj.js → IconAccompaniedMinorNone-DMb-bSCG.js} +1 -1
  3. package/dist/{IconAccompaniedMinorOne-CDMqq14b.js → IconAccompaniedMinorOne-C9ORHm66.js} +1 -1
  4. package/dist/{IconAddReceipt-DRpGiWBU.js → IconAddReceipt-CeJlKuX2.js} +1 -1
  5. package/dist/{IconAirportTerminal-8k-3lKjb.js → IconAirportTerminal-D3p4CRpN.js} +1 -1
  6. package/dist/{IconArrival-m6HnOVje.js → IconArrival-C3oPAqgQ.js} +1 -1
  7. package/dist/IconBaggageCabinNone-valcCKfd.js +22 -0
  8. package/dist/IconBaggageCheckedNone-oq4yx5cO.js +22 -0
  9. package/dist/IconBaggagePersonalNone-BovIoK0M.js +20 -0
  10. package/dist/{IconBroadcast-B13UworG.js → IconBroadcast-CqdgVQaO.js} +1 -1
  11. package/dist/{IconCabinBag-CNnzHz2B.js → IconCabinBag-CMrtn-s6.js} +1 -1
  12. package/dist/IconCalendar-DmUZ-Du1.js +30 -0
  13. package/dist/IconCalendarDelay-DHaiharm.js +22 -0
  14. package/dist/{IconCheckedBaggage-CkxUDHe9.js → IconCheckedBaggage-OeOjHxe7.js} +1 -1
  15. package/dist/{IconCheckedBaggage20-DEtphLSa.js → IconCheckedBaggage20-CXeWuJgc.js} +1 -1
  16. package/dist/{IconCheckedBaggage30-CmAddx5h.js → IconCheckedBaggage30-Cartaaei.js} +1 -1
  17. package/dist/{IconChild-OReHyUco.js → IconChild-ChjkS7Gd.js} +1 -1
  18. package/dist/{IconContact-D2N23RZ5.js → IconContact-CtOxYQIs.js} +1 -1
  19. package/dist/{IconDeparture-D10LaXRX.js → IconDeparture-DJxClL94.js} +1 -1
  20. package/dist/{IconDistribution-SpPiru9I.js → IconDistribution-BmCLzb9p.js} +1 -1
  21. package/dist/{IconDistributionClosed-Bzqe7nju.js → IconDistributionClosed-BMjqoyt9.js} +1 -1
  22. package/dist/{IconDistributionExclusivePair-CjPM-_R1.js → IconDistributionExclusivePair-D71kgwyk.js} +1 -1
  23. package/dist/{IconDistributionSided-DehjCN0D.js → IconDistributionSided-Du56cPXR.js} +1 -1
  24. package/dist/{IconDistributionSupplySided-DWCyXqd1.js → IconDistributionSupplySided-BY9ACIGQ.js} +1 -1
  25. package/dist/{IconDynamicContent-BvzbgXvW.js → IconDynamicContent-DoYbB86x.js} +1 -1
  26. package/dist/IconEndDate-CVABdl-P.js +22 -0
  27. package/dist/{IconFares-zARDpPNl.js → IconFares-BXnx8WJa.js} +1 -1
  28. package/dist/{IconFaresOutlined-DLFV8nwg.js → IconFaresOutlined-CjJhZUKX.js} +1 -1
  29. package/dist/{IconFemale-Ba4uoI-S.js → IconFemale-D4lMoNKt.js} +1 -1
  30. package/dist/{IconFindConversation-d0pP3wG9.js → IconFindConversation-CYdB5hW8.js} +1 -1
  31. package/dist/{IconFire-CXzWKoMB.js → IconFire-Bh3vQ1A3.js} +1 -1
  32. package/dist/{IconFlight-Cof8M5dO.js → IconFlight-RyDIRwoI.js} +1 -1
  33. package/dist/{IconFlightReturn-CA9iGMcW.js → IconFlightReturn-DN7K5zxX.js} +1 -1
  34. package/dist/IconFlightSchedule-DAX_cnvF.js +28 -0
  35. package/dist/{IconHandHeart-CCLKnMOm.js → IconHandHeart-C5jxr29k.js} +1 -1
  36. package/dist/{IconHistory-DI6WD_3J.js → IconHistory-CuJwcjfY.js} +1 -1
  37. package/dist/{IconHourGlass-BorNLEca.js → IconHourGlass-DyrZPbXz.js} +1 -1
  38. package/dist/{IconIdCard-DhbhBkul.js → IconIdCard-lBDLYRPq.js} +1 -1
  39. package/dist/{IconInfant-D4EztT9g.js → IconInfant-E19ozPuk.js} +1 -1
  40. package/dist/{IconItinerary-Bhj_lgG2.js → IconItinerary-5AEG0f9f.js} +1 -1
  41. package/dist/{IconLeave-BvpY7gdD.js → IconLeave-XuFJRd-0.js} +1 -1
  42. package/dist/{IconMale-RMd_9ZSg.js → IconMale-R2ZgQj0s.js} +1 -1
  43. package/dist/{IconMultiSegments-DROUj0t5.js → IconMultiSegments-DfiqdUEm.js} +1 -1
  44. package/dist/IconNoPassport-h-6DjTcc.js +22 -0
  45. package/dist/{IconNoRefund-yNAZr7uX.js → IconNoRefund-C5R_Zxke.js} +1 -1
  46. package/dist/IconNoSeat-C-XnWQk8.js +23 -0
  47. package/dist/{IconNotion-CpZhGILz.js → IconNotion-pdx45QBU.js} +1 -1
  48. package/dist/{IconOffline-Bf1mw_1N.js → IconOffline-EG6mJ-Fs.js} +1 -1
  49. package/dist/{IconOneWay-6oGoLo57.js → IconOneWay-CX6CckSB.js} +2 -2
  50. package/dist/{IconPaid-B3dvioAR.js → IconPaid-BJhBGPy9.js} +1 -1
  51. package/dist/IconPassport-C6THdLYf.js +37 -0
  52. package/dist/{IconPayout-b3TcXwjA.js → IconPayout-MS-qRRR0.js} +1 -1
  53. package/dist/IconPlug-yYpQdJgj.js +22 -0
  54. package/dist/IconPlugOff-DSGcBog-.js +23 -0
  55. package/dist/{IconReceipt-Dh454941.js → IconReceipt-ChU6nBry.js} +1 -1
  56. package/dist/IconRecurrence-DtwCmoXo.js +22 -0
  57. package/dist/{IconRefund-D-FNjukU.js → IconRefund-D1wQXsZj.js} +1 -1
  58. package/dist/{IconRoundTrip-BqVPrNwg.js → IconRoundTrip-DhPU15r6.js} +1 -1
  59. package/dist/{IconRouteNoStop-CZ_QeOIY.js → IconRouteNoStop-C5b0NI9V.js} +1 -1
  60. package/dist/{IconRouteOneStop-DGpLAQmQ.js → IconRouteOneStop-CDL4AJoN.js} +1 -1
  61. package/dist/IconScheduleChange-CasvbB9p.js +22 -0
  62. package/dist/{IconSeatEmpty-BwyVwYQZ.js → IconSeatEmpty-CUDMQzqk.js} +1 -1
  63. package/dist/{IconSeatSold-B_SNoTs-.js → IconSeatSold-mwtkmlhT.js} +1 -1
  64. package/dist/{IconSeatTotal-DUEF7k6I.js → IconSeatTotal-BPegCOjA.js} +1 -1
  65. package/dist/IconStartDate-DoPJpEly.js +22 -0
  66. package/dist/{IconTemplate-D1ACYaHI.js → IconTemplate-CQH8r3U7.js} +1 -1
  67. package/dist/{IconTicket-5Z4b83BP.js → IconTicket-mONYGHBg.js} +1 -1
  68. package/dist/{IconTimer-DbcddAPo.js → IconTimer-BxR1ymxu.js} +1 -1
  69. package/dist/{IconTrafficControl-CEzhRpZt.js → IconTrafficControl-AcQHu-Dm.js} +1 -1
  70. package/dist/{index-DbgX3-2I.js → index-CjeXy6n3.js} +17600 -18506
  71. package/dist/pimp.es.js +1 -1
  72. package/dist/pimp.umd.js +23 -23
  73. package/dist/style.css +1 -1
  74. package/package.json +2 -1
  75. package/src/components/{core/BaseInputLabel.vue → BaseInputLabel.vue} +9 -15
  76. package/src/components/{core/BaseSelectClearButton.vue → BaseSelectClearButton.vue} +2 -2
  77. package/src/components/{atomic-elements/CpAirlineLogo.vue → CpAirlineLogo.vue} +9 -10
  78. package/src/components/{feedback-indicators/CpAlert.vue → CpAlert.vue} +16 -27
  79. package/src/components/{atomic-elements/CpBadge.vue → CpBadge.vue} +27 -44
  80. package/src/components/{buttons/CpButton.vue → CpButton.vue} +63 -104
  81. package/src/components/{date-pickers/CpCalendar.vue → CpCalendar.vue} +157 -156
  82. package/src/components/{toggles/CpCheckbox.vue → CpCheckbox.vue} +45 -54
  83. package/src/components/{date-pickers/CpDate.vue → CpDate.vue} +202 -212
  84. package/src/components/CpDatepicker.vue +203 -0
  85. package/src/components/{atomic-elements/CpDialog.vue → CpDialog.vue} +14 -9
  86. package/src/components/{typography/CpHeading.vue → CpHeading.vue} +11 -31
  87. package/src/components/{visual/CpIcon.vue → CpIcon.vue} +2 -1
  88. package/src/components/{inputs/CpInput.vue → CpInput.vue} +41 -58
  89. package/src/components/{feedback-indicators/CpLoader.vue → CpLoader.vue} +7 -8
  90. package/src/components/{selects/CpMultiselect.vue → CpMultiselect.vue} +60 -91
  91. package/src/components/{atomic-elements/CpPartnerBadge.vue → CpPartnerBadge.vue} +12 -20
  92. package/src/components/{toggles/CpRadio.vue → CpRadio.vue} +47 -58
  93. package/src/components/{selects/CpSelect.vue → CpSelect.vue} +74 -94
  94. package/src/components/{selects/CpSelectMenu.vue → CpSelectMenu.vue} +94 -96
  95. package/src/components/{toggles/CpSwitch.vue → CpSwitch.vue} +51 -67
  96. package/src/components/{lists-and-table/CpTable.vue → CpTable.vue} +159 -113
  97. package/src/components/{lists-and-table/CpTableEmptyState.vue → CpTableEmptyState.vue} +5 -8
  98. package/src/components/{inputs/CpTextarea.vue → CpTextarea.vue} +32 -52
  99. package/src/components/CpToaster.vue +377 -0
  100. package/src/components/{atomic-elements/CpTooltip.vue → CpTooltip.vue} +12 -11
  101. package/src/components/TransitionExpand.vue +70 -0
  102. package/src/components/icons/IconBaggageCabinNone.vue +24 -0
  103. package/src/components/icons/IconBaggageCheckedNone.vue +25 -0
  104. package/src/components/icons/IconBaggagePersonalNone.vue +33 -0
  105. package/src/components/icons/IconCalendar.vue +17 -0
  106. package/src/components/icons/IconCalendarDelay.vue +21 -0
  107. package/src/components/icons/IconEndDate.vue +19 -0
  108. package/src/components/icons/IconFlightSchedule.vue +23 -0
  109. package/src/components/icons/IconNoPassport.vue +23 -24
  110. package/src/components/icons/IconNoSeat.vue +18 -0
  111. package/src/components/icons/IconOneWay.vue +1 -1
  112. package/src/components/icons/IconPassport.vue +15 -22
  113. package/src/components/icons/IconPlug.vue +17 -0
  114. package/src/components/icons/IconPlugOff.vue +18 -0
  115. package/src/components/icons/IconRecurrence.vue +17 -8
  116. package/src/components/icons/IconScheduleChange.vue +17 -26
  117. package/src/components/icons/IconStartDate.vue +19 -0
  118. package/src/components/index.ts +43 -55
  119. package/src/constants/{src/CpCustomIcons.ts → CpCustomIcons.ts} +13 -2
  120. package/src/constants/CpTableConfig.ts +12 -0
  121. package/src/constants/Heading.ts +8 -0
  122. package/src/{utils/constants/src/Intent.js → constants/Intent.ts} +1 -1
  123. package/src/constants/PartnerTypes.ts +6 -0
  124. package/src/constants/Position.ts +10 -0
  125. package/src/constants/Sizes.ts +5 -0
  126. package/src/constants/colors/Colors.ts +10 -0
  127. package/src/constants/colors/ToggleColors.ts +6 -0
  128. package/src/constants/index.ts +10 -5
  129. package/src/directives/ClickOutside.ts +17 -0
  130. package/src/directives/{ResizeSelect.js → ResizeSelect.ts} +3 -3
  131. package/src/helpers/{dom.js → dom.ts} +13 -9
  132. package/src/helpers/{index.js → index.ts} +13 -3
  133. package/src/helpers/object.ts +9 -0
  134. package/src/helpers/string/src/camelize.ts +6 -0
  135. package/src/helpers/string/src/{decamelize.js → decamelize.ts} +1 -1
  136. package/src/libs/CoreDatepicker.vue +4 -4
  137. package/src/plugins/toaster.ts +71 -0
  138. package/src/stories/BaseInputLabel.stories.ts +2 -1
  139. package/src/stories/CpAirlineLogo.stories.ts +1 -1
  140. package/src/stories/CpAlert.stories.ts +2 -1
  141. package/src/stories/CpBadge.stories.ts +1 -1
  142. package/src/stories/CpButton.stories.ts +1 -1
  143. package/src/stories/CpCheckbox.stories.ts +4 -2
  144. package/src/stories/CpDate.stories.ts +4 -2
  145. package/src/stories/CpDatepicker.stories.ts +4 -2
  146. package/src/stories/CpDialog.stories.ts +3 -2
  147. package/src/stories/CpHeading.stories.ts +2 -1
  148. package/src/stories/CpIcon.stories.ts +3 -1
  149. package/src/stories/CpInput.stories.ts +4 -2
  150. package/src/stories/CpLoader.stories.ts +2 -1
  151. package/src/stories/CpMultiselect.stories.ts +3 -2
  152. package/src/stories/CpPartnerBadge.stories.ts +2 -2
  153. package/src/stories/CpRadio.stories.ts +4 -2
  154. package/src/stories/CpSelect.stories.ts +4 -2
  155. package/src/stories/CpSelectMenu.stories.ts +4 -2
  156. package/src/stories/CpSwitch.stories.ts +4 -2
  157. package/src/stories/CpTable.stories.ts +9 -2
  158. package/src/stories/CpTableEmptyState.stories.ts +2 -1
  159. package/src/stories/CpTextarea.stories.ts +4 -2
  160. package/src/stories/CpToaster.stories.ts +2 -1
  161. package/src/stories/CpTooltip.stories.ts +2 -1
  162. package/src/stories/TransitionExpand.stories.ts +4 -2
  163. package/src/types/luxon.d.ts +1 -0
  164. package/src/vendors/ff-polyfill.ts +38 -0
  165. package/vitest.workspace.js +1 -3
  166. package/dist/IconNoPassport-DBmaQH_g.js +0 -18
  167. package/dist/IconPassport-5SwUf6_R.js +0 -20
  168. package/dist/IconRecurrence-CXVkBJ3i.js +0 -24
  169. package/dist/IconScheduleChange-CEIGEhU4.js +0 -19
  170. package/src/components/date-pickers/CpDatepicker.vue +0 -229
  171. package/src/components/feedback-indicators/CpToaster.vue +0 -372
  172. package/src/components/helpers-utilities/TransitionExpand.vue +0 -72
  173. package/src/constants/src/CpTableConfig.ts +0 -14
  174. package/src/constants/src/Position.ts +0 -10
  175. package/src/constants/src/colors/Colors.ts +0 -10
  176. package/src/constants/src/colors/ToggleColors.ts +0 -6
  177. package/src/directives/ClickOutside.js +0 -13
  178. package/src/helpers/object.js +0 -9
  179. package/src/helpers/string/src/camelize.js +0 -6
  180. package/src/plugins/toaster.js +0 -61
  181. package/src/utils/constants/index.js +0 -3
  182. package/src/utils/constants/src/PartnerTypes.js +0 -6
  183. package/src/utils/constants/src/Sizes.js +0 -5
  184. package/src/vendors/ff-polyfill.js +0 -36
  185. /package/src/components/{atomic-elements/CpDialogWrapper.vue → CpDialogWrapper.vue} +0 -0
  186. /package/src/components/{logo/Pimp.vue → Pimp.vue} +0 -0
  187. /package/src/helpers/string/{index.js → index.ts} +0 -0
@@ -52,232 +52,222 @@
52
52
  </div>
53
53
  </template>
54
54
 
55
- <script>
55
+ <script setup lang="ts">
56
56
  import { Info, DateTime } from 'luxon'
57
+ import { ref, computed, watch } from 'vue'
57
58
 
58
59
  import { randomString, capitalizeFirstLetter } from '@/helpers'
59
60
 
60
61
  const HUMAN_MAX_AGE = 120
61
62
 
62
- export default {
63
- props: {
64
- modelValue: {
65
- type: [String, Date],
66
- default: '',
67
- },
68
- minDate: {
69
- type: [String, Date],
70
- default: DateTime.now().minus({ year: HUMAN_MAX_AGE }).toISO(),
71
- },
72
- maxDate: {
73
- type: [String, Date],
74
- default: DateTime.now().toISO(),
75
- },
76
- label: {
77
- type: String,
78
- default: '',
79
- },
80
- required: {
81
- type: Boolean,
82
- default: false,
83
- },
84
- disabled: {
85
- type: Boolean,
86
- default: false,
87
- },
88
- isInvalid: {
89
- type: Boolean,
90
- default: false,
91
- },
92
- errorMessage: {
93
- type: String,
94
- default: '',
95
- },
96
- displayErrorMessage: {
97
- type: Boolean,
98
- default: true,
99
- },
100
- autocompleteBirthday: {
101
- type: Boolean,
102
- default: false,
103
- },
104
- locale: {
105
- type: String,
106
- default: () => {
107
- return navigator.language
108
- },
109
- },
110
- inputsOptions: {
111
- type: Object,
112
- default: () => {},
113
- },
114
- },
115
- emits: ['update:modelValue', 'on-validation'],
116
- data() {
63
+ interface InputsOptions {
64
+ dayInputPlaceholder?: string
65
+ monthInputPlaceholder?: string
66
+ yearInputPlaceholder?: string
67
+ }
68
+
69
+ interface Props {
70
+ autocompleteBirthday?: boolean
71
+ disabled?: boolean
72
+ displayErrorMessage?: boolean
73
+ errorMessage?: string
74
+ inputsOptions?: InputsOptions
75
+ isInvalid?: boolean
76
+ label?: string
77
+ locale?: string
78
+ maxDate?: string | Date
79
+ minDate?: string | Date
80
+ modelValue?: string | Date
81
+ required?: boolean
82
+ }
83
+
84
+ interface Emits {
85
+ (e: 'update:modelValue', value: string): void
86
+ (e: 'on-validation', value: boolean): void
87
+ }
88
+
89
+ const props = withDefaults(defineProps<Props>(), {
90
+ modelValue: '',
91
+ minDate: () => DateTime.now().minus({ year: HUMAN_MAX_AGE }).toISO(),
92
+ maxDate: () => DateTime.now().toISO(),
93
+ label: '',
94
+ required: false,
95
+ disabled: false,
96
+ isInvalid: false,
97
+ errorMessage: '',
98
+ displayErrorMessage: true,
99
+ autocompleteBirthday: false,
100
+ locale: () => navigator.language,
101
+ inputsOptions: () => ({}),
102
+ })
103
+
104
+ const emit = defineEmits<Emits>()
105
+
106
+ const initDateToken = (token: 'day' | 'month' | 'year'): string => {
107
+ if (DateTime.fromISO(props.modelValue).invalid) return ''
108
+
109
+ return DateTime.fromISO(props.modelValue)[token]
110
+ }
111
+
112
+ const day = ref(initDateToken('day'))
113
+ const month = ref(initDateToken('month'))
114
+ const year = ref(initDateToken('year'))
115
+
116
+ const capitalizedLabel = computed(() => capitalizeFirstLetter(props.label))
117
+
118
+ const cpDateId = computed(() => randomString())
119
+
120
+ const minYear = computed(() => isoMinDate.value.year)
121
+
122
+ const maxYear = computed(() => isoMaxDate.value.year)
123
+
124
+ const monthMaxDay = computed(() => {
125
+ const date = DateTime.fromObject({
126
+ year: year.value && year.value.length <= 4 ? Number(year.value) : DateTime.now().year,
127
+ month: month.value ? Number(month.value) : DateTime.now().month,
128
+ day: 1,
129
+ })
130
+
131
+ return date.daysInMonth
132
+ })
133
+
134
+ const months = computed(() => {
135
+ const rawLocalizedMonths = Info.months('long', { locale: props.locale })
136
+
137
+ return rawLocalizedMonths.map((month: string, index: number) => {
117
138
  return {
118
- day: this.initDateToken('day'),
119
- month: this.initDateToken('month'),
120
- year: this.initDateToken('year'),
139
+ label: capitalizeFirstLetter(month),
140
+ value: index + 1,
121
141
  }
122
- },
123
- computed: {
124
- capitalizedLabel() {
125
- return capitalizeFirstLetter(this.label)
126
- },
127
- cpDateId() {
128
- return randomString()
129
- },
130
- minYear() {
131
- return this.isoMinDate.year
132
- },
133
- maxYear() {
134
- return this.isoMaxDate.year
135
- },
136
- monthMaxDay() {
137
- const date = DateTime.fromObject({
138
- year: this.year && this.year.length <= 4 ? Number(this.year) : DateTime.now().year,
139
- month: this.month ? Number(this.month) : DateTime.now().month,
140
- day: 1,
141
- })
142
-
143
- return date.daysInMonth
144
- },
145
- months() {
146
- const rawLocalizedMonths = Info.months('long', { locale: this.locale })
147
-
148
- return rawLocalizedMonths.map((month, index) => {
149
- return {
150
- label: capitalizeFirstLetter(month),
151
- value: index + 1,
152
- }
153
- })
154
- },
155
- isoDate() {
156
- return DateTime.fromObject({
157
- year: Number(this.year),
158
- month: Number(this.month),
159
- day: Number(this.day),
160
- }).toISODate()
161
- },
162
- isoMinDate() {
163
- return DateTime.fromISO(this.minDate)
164
- },
165
- isoMaxDate() {
166
- return DateTime.fromISO(this.maxDate)
167
- },
168
- isDateAfterMinDate() {
169
- return this.isoDate >= this.isoMinDate.toISODate()
170
- },
171
- isDateBeforeMaxDate() {
172
- return this.isoDate <= this.isoMaxDate.toISODate()
173
- },
174
- areInputsEmpty() {
175
- return this.day === '' && this.month === '' && this.year === ''
176
- },
177
- isDateValid() {
178
- if (this.areInputsEmpty && !this.required) return true
179
-
180
- return (
181
- !this.isInvalid &&
182
- this.isDayValid &&
183
- this.isMonthValid &&
184
- this.isYearValid &&
185
- this.isDateBeforeMaxDate &&
186
- this.isDateAfterMinDate
187
- )
188
- },
189
- isDayValid() {
190
- return this.day >= 1 && this.day <= this.monthMaxDay
191
- },
192
- isMonthValid() {
193
- return !!this.month
194
- },
195
- isYearValid() {
196
- return this.year >= this.minYear && this.year <= this.maxYear
197
- },
198
- advancedErrorMessage() {
199
- if (this.isDateValid || !this.displayErrorMessage) return ''
200
-
201
- if (this.errorMessage) return this.errorMessage
202
-
203
- if (!this.isMonthValid) {
204
- return 'Month is required.'
205
- }
142
+ })
143
+ })
144
+
145
+ const isoDate = computed(() => {
146
+ return DateTime.fromObject({
147
+ year: Number(year.value),
148
+ month: Number(month.value),
149
+ day: Number(day.value),
150
+ }).toISODate()
151
+ })
152
+
153
+ const isoMinDate = computed(() => {
154
+ return DateTime.fromISO(props.minDate)
155
+ })
156
+
157
+ const isoMaxDate = computed(() => {
158
+ return DateTime.fromISO(props.maxDate)
159
+ })
160
+
161
+ const isDateAfterMinDate = computed(() => {
162
+ return isoDate.value >= isoMinDate.value.toISODate()
163
+ })
164
+
165
+ const isDateBeforeMaxDate = computed(() => {
166
+ return isoDate.value <= isoMaxDate.value.toISODate()
167
+ })
168
+
169
+ const areInputsEmpty = computed(() => {
170
+ return day.value === '' && month.value === '' && year.value === ''
171
+ })
172
+
173
+ const isDateValid = computed(() => {
174
+ if (areInputsEmpty.value && !props.required) return true
175
+
176
+ return (
177
+ !props.isInvalid &&
178
+ isDayValid.value &&
179
+ isMonthValid.value &&
180
+ isYearValid.value &&
181
+ isDateBeforeMaxDate.value &&
182
+ isDateAfterMinDate.value
183
+ )
184
+ })
185
+
186
+ const isDayValid = computed(() => {
187
+ return Number(day.value) >= 1 && Number(day.value) <= monthMaxDay.value
188
+ })
189
+
190
+ const isMonthValid = computed(() => {
191
+ return !!month.value
192
+ })
193
+
194
+ const isYearValid = computed(() => {
195
+ return Number(year.value) >= minYear.value && Number(year.value) <= maxYear.value
196
+ })
197
+
198
+ const advancedErrorMessage = computed(() => {
199
+ if (isDateValid.value || !props.displayErrorMessage) return ''
200
+
201
+ if (props.errorMessage) return props.errorMessage
202
+
203
+ if (!isMonthValid.value) {
204
+ return 'Month is required.'
205
+ }
206
206
 
207
- if (!this.isDayValid) {
208
- return `Day must be in the range 1 – ${this.monthMaxDay}.`
209
- }
207
+ if (!isDayValid.value) {
208
+ return `Day must be in the range 1 – ${monthMaxDay.value}.`
209
+ }
210
210
 
211
- if (!this.isYearValid) {
212
- return `Year must be in the range ${this.minYear} – ${this.maxYear}.`
213
- }
211
+ if (!isYearValid.value) {
212
+ return `Year must be in the range ${minYear.value} – ${maxYear.value}.`
213
+ }
214
214
 
215
- if (!this.isDateBeforeMaxDate) {
216
- const formattedMaxDate = this.isoMaxDate.toFormat('DDD')
217
- return `The date can't be after ${formattedMaxDate}.`
218
- }
215
+ if (!isDateBeforeMaxDate.value) {
216
+ const formattedMaxDate = isoMaxDate.value.toFormat('DDD')
217
+ return `The date can't be after ${formattedMaxDate}.`
218
+ }
219
219
 
220
- if (!this.isDateAfterMinDate) {
221
- const formattedMinDate = this.isoMinDate.toFormat('DDD')
222
- return `The date can't be before ${formattedMinDate}.`
223
- }
220
+ if (!isDateAfterMinDate.value) {
221
+ const formattedMinDate = isoMinDate.value.toFormat('DDD')
222
+ return `The date can't be before ${formattedMinDate}.`
223
+ }
224
224
 
225
- return ''
226
- },
227
- dynamicClasses() {
228
- return {
229
- 'cpDate--isInvalid': !this.isDateValid,
230
- 'cpDate--isDisabled': this.disabled,
231
- }
232
- },
233
- selectDynamicClass() {
234
- return {
235
- 'cpDate__month--isEmpty': !this.month,
236
- }
237
- },
238
- autocompleteFields() {
239
- if (!this.autocompleteBirthday) return 'off'
240
-
241
- return {
242
- day: 'bday-day',
243
- month: 'bday-month',
244
- year: 'bday-year',
245
- }
246
- },
247
- dayInputPlaceholder() {
248
- return this.inputsOptions?.dayInputPlaceholder || 'DD'
249
- },
250
- monthInputPlaceholder() {
251
- return this.inputsOptions?.monthInputPlaceholder || 'Months'
252
- },
253
- yearInputPlaceholder() {
254
- return this.inputsOptions?.yearInputPlaceholder || 'YYYY'
255
- },
256
- },
257
- watch: {
258
- day() {
259
- this.handleUpdate()
260
- },
261
- month() {
262
- this.handleUpdate()
263
- },
264
- year() {
265
- this.handleUpdate()
266
- },
267
- },
268
- methods: {
269
- initDateToken(token) {
270
- if (DateTime.fromISO(this.modelValue).invalid) return ''
271
-
272
- return DateTime.fromISO(this.modelValue)[token]
273
- },
274
- handleUpdate() {
275
- this.$emit('update:modelValue', this.isoDate)
276
-
277
- this.$emit('on-validation', this.isDateValid)
278
- },
279
- },
225
+ return ''
226
+ })
227
+
228
+ const dynamicClasses = computed(() => {
229
+ return {
230
+ 'cpDate--isInvalid': !isDateValid.value,
231
+ 'cpDate--isDisabled': props.disabled,
232
+ }
233
+ })
234
+
235
+ const selectDynamicClass = computed(() => {
236
+ return {
237
+ 'cpDate__month--isEmpty': !month.value,
238
+ }
239
+ })
240
+
241
+ const autocompleteFields = computed(() => {
242
+ if (!props.autocompleteBirthday) return 'off'
243
+
244
+ return {
245
+ day: 'bday-day',
246
+ month: 'bday-month',
247
+ year: 'bday-year',
248
+ }
249
+ })
250
+
251
+ const dayInputPlaceholder = computed(() => {
252
+ return props.inputsOptions?.dayInputPlaceholder || 'DD'
253
+ })
254
+
255
+ const monthInputPlaceholder = computed(() => {
256
+ return props.inputsOptions?.monthInputPlaceholder || 'Months'
257
+ })
258
+
259
+ const yearInputPlaceholder = computed(() => {
260
+ return props.inputsOptions?.yearInputPlaceholder || 'YYYY'
261
+ })
262
+
263
+ const handleUpdate = (): void => {
264
+ emit('update:modelValue', isoDate.value)
265
+ emit('on-validation', isDateValid.value)
280
266
  }
267
+
268
+ watch(day, handleUpdate)
269
+ watch(month, handleUpdate)
270
+ watch(year, handleUpdate)
281
271
  </script>
282
272
 
283
273
  <style lang="scss">
@@ -0,0 +1,203 @@
1
+ <template>
2
+ <div class="cpDatepicker">
3
+ <cp-input
4
+ v-show="!isInline"
5
+ :id="datePickerReferenceId"
6
+ :model-value="inputComputedValue"
7
+ type="text"
8
+ :placeholder="placeholder"
9
+ :is-invalid="isError"
10
+ :error-message="errorMessage"
11
+ :disabled="isDisabled"
12
+ :label="label"
13
+ class="cpDatepicker__input"
14
+ />
15
+ <core-datepicker
16
+ :date-one="dateOne"
17
+ :date-two="dateTwo"
18
+ :trigger-element-id="datePickerReferenceId"
19
+ :close-after-select="closeAfterSelect"
20
+ :mode="mode"
21
+ :inline="isInline"
22
+ :months-to-show="numberOfMonths"
23
+ :min-date="computedMinDate"
24
+ :max-date="maxDate"
25
+ :locale="locale"
26
+ class="cpDatepicker__datepicker"
27
+ :class="{ 'cpDatepicker__datepicker--isInline': isInline }"
28
+ @date-one-selected="onDateOneSelected"
29
+ @date-two-selected="onDateTwoSelected"
30
+ @opened="() => (isDisabled = true)"
31
+ @closed="() => (isDisabled = false)"
32
+ />
33
+ </div>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { DateTime } from 'luxon'
38
+ import { ref, computed, watch } from 'vue'
39
+
40
+ import CpInput from '@/components/CpInput.vue'
41
+
42
+ import { randomString, formatDates } from '@/helpers'
43
+ import CoreDatepicker from '@/libs/CoreDatepicker.vue'
44
+
45
+ type DatepickerMode = 'range' | 'single'
46
+
47
+ interface Props {
48
+ allowPastDates?: boolean
49
+ closeAfterSelect?: boolean
50
+ errorMessage?: string
51
+ initDateOne?: string
52
+ initDateTwo?: string
53
+ inputValue?: string
54
+ isError?: boolean
55
+ isInline?: boolean
56
+ label?: string
57
+ locale?: string
58
+ maxDate?: string | Date
59
+ minDate?: string | Date
60
+ mode?: DatepickerMode
61
+ placeholder?: string
62
+ singleMonth?: boolean
63
+ triggerElementId?: string
64
+ }
65
+
66
+ interface Emits {
67
+ (e: 'dates', dates: string[]): void
68
+ }
69
+
70
+ const props = withDefaults(defineProps<Props>(), {
71
+ triggerElementId: '',
72
+ mode: 'single',
73
+ closeAfterSelect: true,
74
+ label: '',
75
+ placeholder: 'Select a date',
76
+ inputValue: '',
77
+ isError: false,
78
+ errorMessage: '',
79
+ initDateOne: '',
80
+ initDateTwo: '',
81
+ minDate: () => DateTime.local().toISODate(),
82
+ maxDate: '',
83
+ allowPastDates: false,
84
+ isInline: false,
85
+ singleMonth: false,
86
+ locale: () => navigator.language,
87
+ })
88
+
89
+ const emit = defineEmits<Emits>()
90
+
91
+ const humanFormat = 'EEE DD'
92
+ const dateOne = ref(props.initDateOne || '')
93
+ const dateTwo = ref(props.mode === 'range' ? props.initDateTwo : '')
94
+ const isDisabled = ref(false)
95
+ const datePickerReferenceId = ref(props.triggerElementId || randomString())
96
+
97
+ const inputComputedValue = computed(() => {
98
+ if (props.inputValue) return props.inputValue
99
+
100
+ return formatDates({
101
+ dateOne: dateOne.value,
102
+ dateTwo: dateTwo.value,
103
+ format: humanFormat,
104
+ locale: props.locale,
105
+ })
106
+ })
107
+
108
+ const numberOfMonths = computed(() => {
109
+ return props.singleMonth ? 1 : 2
110
+ })
111
+
112
+ const computedMinDate = computed(() => {
113
+ return props.allowPastDates ? '' : props.minDate
114
+ })
115
+
116
+ const onDateOneSelected = (date: string) => selectDate('dateOne', date)
117
+ const onDateTwoSelected = (date: string) => selectDate('dateTwo', date)
118
+
119
+ const selectDate = (dateType: 'dateOne' | 'dateTwo', dateValue: string): void => {
120
+ if (dateType === 'dateOne') {
121
+ dateOne.value = dateValue
122
+ } else {
123
+ dateTwo.value = dateValue
124
+ }
125
+ emit('dates', [dateOne.value, ...(dateTwo.value ? [dateTwo.value] : [])])
126
+ }
127
+
128
+ const updateDateValue = (date: 'dateOne' | 'dateTwo', newValue: string, oldValue: string): void => {
129
+ if (newValue !== oldValue) {
130
+ if (date === 'dateOne') {
131
+ dateOne.value = newValue
132
+ } else {
133
+ dateTwo.value = newValue
134
+ }
135
+ }
136
+ }
137
+
138
+ watch(
139
+ () => props.initDateOne,
140
+ (newValue, oldValue) => {
141
+ updateDateValue('dateOne', newValue, oldValue)
142
+ },
143
+ )
144
+
145
+ watch(
146
+ () => props.initDateTwo,
147
+ (newValue, oldValue) => {
148
+ updateDateValue('dateTwo', newValue, oldValue)
149
+ },
150
+ )
151
+ </script>
152
+
153
+ <style lang="scss">
154
+ .cpDatepicker {
155
+ // Opening transition layout adaptation
156
+ .asd__fade-enter-from {
157
+ transform: translateX(-50%) scale(0.8);
158
+ }
159
+
160
+ .asd__fade-enter-to {
161
+ transform: translateX(-50%) scale(1);
162
+ }
163
+
164
+ &__input input:disabled {
165
+ background-color: colors.$neutral-light;
166
+ }
167
+
168
+ &__datepicker {
169
+ position: absolute;
170
+ left: 50%;
171
+ transform: translateX(-50%);
172
+ }
173
+
174
+ &__datepicker:not(&__datepicker--isInline) {
175
+ margin-top: 10px;
176
+ }
177
+
178
+ @media (min-width: 350px) {
179
+ position: relative;
180
+ }
181
+
182
+ @media (max-width: 767px) and (min-width: 350px) {
183
+ &__datepicker {
184
+ left: 0;
185
+ right: 0;
186
+ transform: initial;
187
+ }
188
+
189
+ &__datepicker:not(&__datepicker--isInline) {
190
+ margin-top: 16px;
191
+ }
192
+
193
+ // Opening transition layout adaptation
194
+ .asd__fade-enter-from {
195
+ transform: scale(0.8);
196
+ }
197
+
198
+ .asd__fade-enter-to {
199
+ transform: scale(1);
200
+ }
201
+ }
202
+ }
203
+ </style>
@@ -22,24 +22,29 @@
22
22
  </div>
23
23
  </template>
24
24
 
25
- <script setup>
25
+ <script setup lang="ts">
26
26
  import { computed, ref, useSlots, onMounted, nextTick, onBeforeUnmount } from 'vue'
27
27
 
28
28
  import { getKeyboardFocusableElements, handleTrapFocus } from '@/helpers/dom'
29
29
 
30
- const props = defineProps({
31
- maxWidth: {
32
- type: Number,
33
- default: 600,
34
- },
30
+ interface Props {
31
+ maxWidth?: number
32
+ }
33
+
34
+ interface Emits {
35
+ (e: 'close'): void
36
+ }
37
+
38
+ const props = withDefaults(defineProps<Props>(), {
39
+ maxWidth: 600,
35
40
  })
36
41
 
37
- const emit = defineEmits(['close'])
42
+ const emit = defineEmits<Emits>()
38
43
 
39
44
  const slots = useSlots()
40
45
 
41
46
  const dialogElement = ref()
42
- const dialogContainer = ref()
47
+ const dialogContainer = ref<HTMLElement>()
43
48
 
44
49
  const dynamicStyle = computed(() => {
45
50
  return { maxWidth: `${props.maxWidth}px` }
@@ -49,7 +54,7 @@ const hasHeaderSlot = computed(() => !!slots.header)
49
54
  const hasFooterSlot = computed(() => !!slots.footer)
50
55
 
51
56
  const onClose = () => emit('close')
52
- const trapFocus = (event) => handleTrapFocus(event, dialogContainer.value)
57
+ const trapFocus = (event: KeyboardEvent) => handleTrapFocus(event, dialogContainer.value)
53
58
 
54
59
  const openDialog = () => dialogElement.value.show()
55
60
  const closeDialog = () => dialogElement.value.close()