@citizenplane/pimp 8.26.1 → 8.27.0

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 (149) hide show
  1. package/dist/{IconAccompaniedMinorEach-CUq3oXbX.js → IconAccompaniedMinorEach-BJYaPpW3.js} +1 -1
  2. package/dist/{IconAccompaniedMinorNone-nZ4eSfTj.js → IconAccompaniedMinorNone-D1JR2Qpd.js} +1 -1
  3. package/dist/{IconAccompaniedMinorOne-CDMqq14b.js → IconAccompaniedMinorOne-BJ3jzEDZ.js} +1 -1
  4. package/dist/{IconAddReceipt-DRpGiWBU.js → IconAddReceipt-BX_va94f.js} +1 -1
  5. package/dist/{IconAirportTerminal-8k-3lKjb.js → IconAirportTerminal-Dzr98nfc.js} +1 -1
  6. package/dist/{IconArrival-m6HnOVje.js → IconArrival-Ced9HrJH.js} +1 -1
  7. package/dist/{IconBroadcast-B13UworG.js → IconBroadcast-BYX44Wak.js} +1 -1
  8. package/dist/{IconCabinBag-CNnzHz2B.js → IconCabinBag-D1Qs952U.js} +1 -1
  9. package/dist/{IconCheckedBaggage-CkxUDHe9.js → IconCheckedBaggage-Q4_SQL9l.js} +1 -1
  10. package/dist/{IconCheckedBaggage20-DEtphLSa.js → IconCheckedBaggage20-DVH1-A0V.js} +1 -1
  11. package/dist/{IconCheckedBaggage30-CmAddx5h.js → IconCheckedBaggage30-DYOAf-7Z.js} +1 -1
  12. package/dist/{IconChild-OReHyUco.js → IconChild-BeCLAr8Y.js} +1 -1
  13. package/dist/{IconContact-D2N23RZ5.js → IconContact-B3r39fyI.js} +1 -1
  14. package/dist/{IconDeparture-D10LaXRX.js → IconDeparture-BflKZUiE.js} +1 -1
  15. package/dist/{IconDistribution-SpPiru9I.js → IconDistribution-CBxQ7UWb.js} +1 -1
  16. package/dist/{IconDistributionClosed-Bzqe7nju.js → IconDistributionClosed-BWp_k24K.js} +1 -1
  17. package/dist/{IconDistributionExclusivePair-CjPM-_R1.js → IconDistributionExclusivePair-erLbcLps.js} +1 -1
  18. package/dist/{IconDistributionSided-DehjCN0D.js → IconDistributionSided-y000n4qB.js} +1 -1
  19. package/dist/{IconDistributionSupplySided-DWCyXqd1.js → IconDistributionSupplySided-7kCvGwnz.js} +1 -1
  20. package/dist/{IconDynamicContent-BvzbgXvW.js → IconDynamicContent-SwBxkPMB.js} +1 -1
  21. package/dist/{IconFares-zARDpPNl.js → IconFares-DTm0Q_RI.js} +1 -1
  22. package/dist/{IconFaresOutlined-DLFV8nwg.js → IconFaresOutlined-BFMo_x9Q.js} +1 -1
  23. package/dist/{IconFemale-Ba4uoI-S.js → IconFemale-Ma0KeaEM.js} +1 -1
  24. package/dist/{IconFindConversation-d0pP3wG9.js → IconFindConversation-CpsDYPgD.js} +1 -1
  25. package/dist/{IconFire-CXzWKoMB.js → IconFire-DECrDnLM.js} +1 -1
  26. package/dist/{IconFlight-Cof8M5dO.js → IconFlight-D5M0A0CM.js} +1 -1
  27. package/dist/{IconFlightReturn-CA9iGMcW.js → IconFlightReturn-CTvqEFME.js} +1 -1
  28. package/dist/{IconHandHeart-CCLKnMOm.js → IconHandHeart-ChgdfXQa.js} +1 -1
  29. package/dist/{IconHistory-DI6WD_3J.js → IconHistory-DpIXDYI5.js} +1 -1
  30. package/dist/{IconHourGlass-BorNLEca.js → IconHourGlass-CIRkFUSM.js} +1 -1
  31. package/dist/{IconIdCard-DhbhBkul.js → IconIdCard-UD5VZsUi.js} +1 -1
  32. package/dist/{IconInfant-D4EztT9g.js → IconInfant-CmLUvWpO.js} +1 -1
  33. package/dist/{IconItinerary-Bhj_lgG2.js → IconItinerary-CY8irele.js} +1 -1
  34. package/dist/{IconLeave-BvpY7gdD.js → IconLeave-C3bpPz6L.js} +1 -1
  35. package/dist/{IconMale-RMd_9ZSg.js → IconMale-x4xdulWB.js} +1 -1
  36. package/dist/{IconMultiSegments-DROUj0t5.js → IconMultiSegments-BhTMfvhQ.js} +1 -1
  37. package/dist/{IconNoPassport-DBmaQH_g.js → IconNoPassport-_Xm76k6b.js} +1 -1
  38. package/dist/{IconNoRefund-yNAZr7uX.js → IconNoRefund-B78s0oyF.js} +1 -1
  39. package/dist/{IconNotion-CpZhGILz.js → IconNotion-C22PTLTU.js} +1 -1
  40. package/dist/{IconOffline-Bf1mw_1N.js → IconOffline-BDzikWE9.js} +1 -1
  41. package/dist/{IconOneWay-6oGoLo57.js → IconOneWay-DlTVxokv.js} +2 -2
  42. package/dist/{IconPaid-B3dvioAR.js → IconPaid-DmGERe85.js} +1 -1
  43. package/dist/{IconPassport-5SwUf6_R.js → IconPassport-6VOlXjxJ.js} +1 -1
  44. package/dist/{IconPayout-b3TcXwjA.js → IconPayout-abr6BXCd.js} +1 -1
  45. package/dist/{IconReceipt-Dh454941.js → IconReceipt-BnTaihcq.js} +1 -1
  46. package/dist/{IconRecurrence-CXVkBJ3i.js → IconRecurrence-C5TPG2ht.js} +1 -1
  47. package/dist/{IconRefund-D-FNjukU.js → IconRefund-Ysv8pyMJ.js} +1 -1
  48. package/dist/{IconRoundTrip-BqVPrNwg.js → IconRoundTrip-CIVDw8LK.js} +1 -1
  49. package/dist/{IconRouteNoStop-CZ_QeOIY.js → IconRouteNoStop-DQrq4gW5.js} +1 -1
  50. package/dist/{IconRouteOneStop-DGpLAQmQ.js → IconRouteOneStop-pzisj4i4.js} +1 -1
  51. package/dist/{IconScheduleChange-CEIGEhU4.js → IconScheduleChange-BONs1AAT.js} +1 -1
  52. package/dist/{IconSeatEmpty-BwyVwYQZ.js → IconSeatEmpty-CHij3aGA.js} +1 -1
  53. package/dist/{IconSeatSold-B_SNoTs-.js → IconSeatSold-QspS_zCh.js} +1 -1
  54. package/dist/{IconSeatTotal-DUEF7k6I.js → IconSeatTotal-DTZ1TcAX.js} +1 -1
  55. package/dist/{IconTemplate-D1ACYaHI.js → IconTemplate-BDmmr-9L.js} +1 -1
  56. package/dist/{IconTicket-5Z4b83BP.js → IconTicket--vVn61Ey.js} +1 -1
  57. package/dist/{IconTimer-DbcddAPo.js → IconTimer-CspKpwqZ.js} +1 -1
  58. package/dist/{IconTrafficControl-CEzhRpZt.js → IconTrafficControl-DBamcJNe.js} +1 -1
  59. package/dist/{index-DbgX3-2I.js → index-C3oHnZQk.js} +9166 -10083
  60. package/dist/pimp.es.js +1 -1
  61. package/dist/pimp.umd.js +17 -17
  62. package/dist/style.css +1 -1
  63. package/package.json +2 -1
  64. package/src/components/atomic-elements/CpAirlineLogo.vue +9 -10
  65. package/src/components/atomic-elements/CpBadge.vue +27 -44
  66. package/src/components/atomic-elements/CpDialog.vue +14 -9
  67. package/src/components/atomic-elements/CpPartnerBadge.vue +12 -20
  68. package/src/components/atomic-elements/CpTooltip.vue +12 -11
  69. package/src/components/buttons/CpButton.vue +63 -104
  70. package/src/components/core/BaseInputLabel.vue +9 -15
  71. package/src/components/core/BaseSelectClearButton.vue +1 -1
  72. package/src/components/date-pickers/CpCalendar.vue +154 -153
  73. package/src/components/date-pickers/CpDate.vue +202 -212
  74. package/src/components/date-pickers/CpDatepicker.vue +112 -138
  75. package/src/components/feedback-indicators/CpAlert.vue +16 -27
  76. package/src/components/feedback-indicators/CpLoader.vue +7 -8
  77. package/src/components/feedback-indicators/CpToaster.vue +197 -192
  78. package/src/components/helpers-utilities/TransitionExpand.vue +31 -33
  79. package/src/components/icons/IconOneWay.vue +1 -1
  80. package/src/components/index.ts +28 -40
  81. package/src/components/inputs/CpInput.vue +40 -57
  82. package/src/components/inputs/CpTextarea.vue +30 -50
  83. package/src/components/lists-and-table/CpTable.vue +159 -113
  84. package/src/components/lists-and-table/CpTableEmptyState.vue +5 -8
  85. package/src/components/selects/CpMultiselect.vue +58 -89
  86. package/src/components/selects/CpSelect.vue +70 -90
  87. package/src/components/selects/CpSelectMenu.vue +94 -96
  88. package/src/components/toggles/CpCheckbox.vue +45 -54
  89. package/src/components/toggles/CpRadio.vue +47 -58
  90. package/src/components/toggles/CpSwitch.vue +51 -67
  91. package/src/components/typography/CpHeading.vue +11 -31
  92. package/src/components/visual/CpIcon.vue +2 -1
  93. package/src/constants/{src/CpCustomIcons.ts → CpCustomIcons.ts} +1 -1
  94. package/src/constants/CpTableConfig.ts +12 -0
  95. package/src/constants/Heading.ts +8 -0
  96. package/src/{utils/constants/src/Intent.js → constants/Intent.ts} +1 -1
  97. package/src/constants/PartnerTypes.ts +6 -0
  98. package/src/constants/Position.ts +10 -0
  99. package/src/constants/Sizes.ts +5 -0
  100. package/src/constants/colors/Colors.ts +10 -0
  101. package/src/constants/colors/ToggleColors.ts +6 -0
  102. package/src/constants/index.ts +10 -5
  103. package/src/directives/ClickOutside.ts +17 -0
  104. package/src/directives/{ResizeSelect.js → ResizeSelect.ts} +3 -3
  105. package/src/helpers/{dom.js → dom.ts} +13 -9
  106. package/src/helpers/{index.js → index.ts} +13 -3
  107. package/src/helpers/object.ts +9 -0
  108. package/src/helpers/string/src/camelize.ts +6 -0
  109. package/src/helpers/string/src/{decamelize.js → decamelize.ts} +1 -1
  110. package/src/libs/CoreDatepicker.vue +4 -4
  111. package/src/plugins/toaster.ts +71 -0
  112. package/src/stories/BaseInputLabel.stories.ts +1 -0
  113. package/src/stories/CpAlert.stories.ts +1 -0
  114. package/src/stories/CpCheckbox.stories.ts +3 -1
  115. package/src/stories/CpDate.stories.ts +3 -1
  116. package/src/stories/CpDatepicker.stories.ts +3 -1
  117. package/src/stories/CpDialog.stories.ts +2 -1
  118. package/src/stories/CpHeading.stories.ts +1 -0
  119. package/src/stories/CpIcon.stories.ts +2 -0
  120. package/src/stories/CpInput.stories.ts +3 -1
  121. package/src/stories/CpLoader.stories.ts +1 -0
  122. package/src/stories/CpMultiselect.stories.ts +2 -1
  123. package/src/stories/CpPartnerBadge.stories.ts +1 -1
  124. package/src/stories/CpRadio.stories.ts +3 -1
  125. package/src/stories/CpSelect.stories.ts +3 -1
  126. package/src/stories/CpSelectMenu.stories.ts +3 -1
  127. package/src/stories/CpSwitch.stories.ts +3 -1
  128. package/src/stories/CpTable.stories.ts +8 -1
  129. package/src/stories/CpTableEmptyState.stories.ts +1 -0
  130. package/src/stories/CpTextarea.stories.ts +3 -1
  131. package/src/stories/CpToaster.stories.ts +1 -0
  132. package/src/stories/CpTooltip.stories.ts +1 -0
  133. package/src/stories/TransitionExpand.stories.ts +3 -1
  134. package/src/types/luxon.d.ts +1 -0
  135. package/src/vendors/ff-polyfill.ts +38 -0
  136. package/vitest.workspace.js +1 -3
  137. package/src/constants/src/CpTableConfig.ts +0 -14
  138. package/src/constants/src/Position.ts +0 -10
  139. package/src/constants/src/colors/Colors.ts +0 -10
  140. package/src/constants/src/colors/ToggleColors.ts +0 -6
  141. package/src/directives/ClickOutside.js +0 -13
  142. package/src/helpers/object.js +0 -9
  143. package/src/helpers/string/src/camelize.js +0 -6
  144. package/src/plugins/toaster.js +0 -61
  145. package/src/utils/constants/index.js +0 -3
  146. package/src/utils/constants/src/PartnerTypes.js +0 -6
  147. package/src/utils/constants/src/Sizes.js +0 -5
  148. package/src/vendors/ff-polyfill.js +0 -36
  149. /package/src/helpers/string/{index.js → index.ts} +0 -0
@@ -10,15 +10,12 @@
10
10
  </div>
11
11
  </template>
12
12
 
13
- <script>
14
- export default {
15
- props: {
16
- placeholder: {
17
- type: String,
18
- required: true,
19
- },
20
- },
13
+ <script setup lang="ts">
14
+ interface Props {
15
+ placeholder: string
21
16
  }
17
+
18
+ defineProps<Props>()
22
19
  </script>
23
20
 
24
21
  <style lang="scss">
@@ -67,96 +67,61 @@
67
67
  </div>
68
68
  </template>
69
69
 
70
- <script setup>
71
- import { ref, computed, onMounted } from 'vue'
72
- import AutoComplete from 'primevue/autocomplete'
73
-
70
+ <script setup lang="ts">
74
71
  import { absolutePosition, getOuterWidth } from '@primeuix/utils/dom'
72
+ import AutoComplete from 'primevue/autocomplete'
73
+ import { ref, computed, onMounted } from 'vue'
75
74
 
76
75
  import BaseInputLabel from '@/components/core/BaseInputLabel.vue'
77
- import TransitionExpand from '@/components/helpers-utilities/TransitionExpand.vue'
78
76
  import BaseSelectClearButton from '@/components/core/BaseSelectClearButton.vue'
77
+ import TransitionExpand from '@/components/helpers-utilities/TransitionExpand.vue'
79
78
 
80
79
  import { isEmpty } from '@/helpers/object'
81
80
 
82
- const props = defineProps({
83
- label: {
84
- type: String,
85
- required: false,
86
- default: '',
87
- },
88
- required: {
89
- type: Boolean,
90
- required: false,
91
- default: false,
92
- },
93
- name: {
94
- type: String,
95
- required: false,
96
- default: '',
97
- },
98
- placeholder: {
99
- type: String,
100
- required: false,
101
- default: '',
102
- },
103
- isInvalid: {
104
- type: Boolean,
105
- required: false,
106
- default: false,
107
- },
108
- isClearable: {
109
- type: Boolean,
110
- required: false,
111
- default: false,
112
- },
113
- isLoading: {
114
- type: Boolean,
115
- required: false,
116
- default: false,
117
- },
118
- disabled: {
119
- type: Boolean,
120
- required: false,
121
- default: false,
122
- },
123
- multiple: {
124
- type: Boolean,
125
- required: false,
126
- default: false,
127
- },
128
- options: {
129
- type: Array,
130
- required: false,
131
- default: () => [],
132
- },
133
- optionLabel: {
134
- type: String,
135
- required: false,
136
- default: 'name',
137
- },
138
- trackBy: {
139
- type: String,
140
- required: false,
141
- default: 'id',
142
- },
143
- emptyMessage: {
144
- type: String,
145
- required: false,
146
- default: 'No results found',
147
- },
148
- errorMessage: {
149
- type: String,
150
- required: false,
151
- default: '',
152
- },
153
- modelValue: {
154
- type: [Array, Object],
155
- required: false,
156
- },
81
+ interface Props {
82
+ disabled?: boolean
83
+ emptyMessage?: string
84
+ errorMessage?: string
85
+ isClearable?: boolean
86
+ isInvalid?: boolean
87
+ isLoading?: boolean
88
+ label?: string
89
+ modelValue?: Record<string, unknown>[] | Record<string, unknown> | null
90
+ multiple?: boolean
91
+ name?: string
92
+ optionLabel?: string
93
+ options?: unknown[]
94
+ placeholder?: string
95
+ required?: boolean
96
+ trackBy?: string
97
+ }
98
+
99
+ const props = withDefaults(defineProps<Props>(), {
100
+ label: '',
101
+ required: false,
102
+ name: '',
103
+ placeholder: '',
104
+ isInvalid: false,
105
+ isClearable: false,
106
+ isLoading: false,
107
+ disabled: false,
108
+ multiple: false,
109
+ options: () => [],
110
+ optionLabel: 'name',
111
+ trackBy: 'id',
112
+ emptyMessage: 'No results found',
113
+ errorMessage: '',
114
+ modelValue: null,
157
115
  })
158
116
 
159
- const emit = defineEmits(['search', 'select', 'clear'])
117
+ interface Emits {
118
+ (e: 'search', query: string): void
119
+ (e: 'select', option: Record<string, unknown>): void
120
+ (e: 'clear'): void
121
+ (e: 'update:modelValue', value: Record<string, unknown> | Record<string, unknown>[] | null): void
122
+ }
123
+
124
+ const emit = defineEmits<Emits>()
160
125
 
161
126
  const selectModel = computed({
162
127
  get() {
@@ -183,7 +148,7 @@ const passThroughConfig = {
183
148
  loader: { class: 'cpMultiselect__hidden' },
184
149
  }
185
150
 
186
- const multiselect = ref(null)
151
+ const multiselect = ref<InstanceType<typeof AutoComplete> | null>(null)
187
152
 
188
153
  const isDropdownOpen = computed(() => multiselect.value?.overlayVisible)
189
154
 
@@ -203,29 +168,33 @@ const displayClearButton = computed(() => {
203
168
  return props.isClearable && !isEmpty(selectModel.value)
204
169
  })
205
170
 
206
- const handleSearch = (event) => emit('search', event.query)
171
+ const handleSearch = (event: { query: string }) => emit('search', event.query)
207
172
  const handleClear = () => (selectModel.value = null)
208
173
 
209
174
  const toggleDropdown = () => {
210
175
  if (isDropdownOpen.value) {
211
- multiselect.value.hide()
176
+ multiselect.value?.hide()
212
177
  } else {
213
- multiselect.value.show()
178
+ multiselect.value?.show()
214
179
  }
215
180
  }
216
181
 
217
- const handleUpdateModelValue = (value) => {
182
+ const handleUpdateModelValue = (value: Record<string, unknown> | null) => {
218
183
  // Autocomplete will set the model value to the query string if not blocked
219
184
  if (!value || typeof value === 'string') {
220
185
  return
221
186
  }
222
187
  }
223
188
 
224
- const overrideAlignOverlay = () => (multiselect.value.alignOverlay = alignOverlay)
189
+ const overrideAlignOverlay = () => {
190
+ if (multiselect.value) {
191
+ multiselect.value.alignOverlay = alignOverlay
192
+ }
193
+ }
225
194
 
226
195
  const alignOverlay = () => {
227
- const target = multiselect.value.$el
228
- if (!multiselect.value.overlay || !target) return
196
+ const target = multiselect.value?.$el
197
+ if (!multiselect.value?.overlay || !target) return
229
198
 
230
199
  multiselect.value.overlay.style.width = `${getOuterWidth(target)}px`
231
200
 
@@ -15,7 +15,7 @@
15
15
  class="cpSelect__inner"
16
16
  @input="handleChange"
17
17
  >
18
- <option :disabled="hideDefaultValue || null" value="">{{ defaultValue }}</option>
18
+ <option :disabled="hideDefaultValue" value="">{{ defaultValue }}</option>
19
19
  <option v-for="(option, index) in options" :key="index" :value="option.value">{{ option.label }}</option>
20
20
  </select>
21
21
  </div>
@@ -32,100 +32,80 @@
32
32
  </div>
33
33
  </template>
34
34
 
35
- <script>
36
- import { randomString } from '@/helpers'
35
+ <script setup lang="ts">
36
+ import { ref, computed, onMounted } from 'vue'
37
37
 
38
38
  import BaseInputLabel from '@/components/core/BaseInputLabel.vue'
39
39
  import TransitionExpand from '@/components/helpers-utilities/TransitionExpand.vue'
40
40
 
41
- import { capitalizeFirstLetter } from '@/helpers'
42
-
43
- export default {
44
- name: 'CpSelect',
45
- components: {
46
- BaseInputLabel,
47
- TransitionExpand,
48
- },
49
- props: {
50
- label: {
51
- type: String,
52
- default: '',
53
- },
54
- modelValue: {
55
- type: [String, Number],
56
- default: '',
57
- },
58
- hideDefaultValue: {
59
- type: Boolean,
60
- default: false,
61
- },
62
- defaultValue: {
63
- type: String,
64
- default: 'Select an option',
65
- },
66
- options: {
67
- type: Array,
68
- required: true,
69
- },
70
- name: {
71
- type: String,
72
- default: null,
73
- },
74
- required: {
75
- type: Boolean,
76
- default: null,
77
- },
78
- disabled: {
79
- type: Boolean,
80
- default: null,
81
- },
82
- autocomplete: {
83
- type: String,
84
- default: 'on',
85
- },
86
- isInvalid: {
87
- type: Boolean,
88
- default: false,
89
- },
90
- errorMessage: {
91
- type: String,
92
- default: '',
93
- },
94
- isLarge: {
95
- type: Boolean,
96
- default: false,
97
- },
98
- },
99
- emits: ['update:modelValue'],
100
- data() {
101
- return {
102
- selectReferenceId: '',
103
- }
104
- },
105
- computed: {
106
- capitalizedLabel() {
107
- return capitalizeFirstLetter(this.label)
108
- },
109
- dynamicClasses() {
110
- return {
111
- 'cpSelect--isInvalid': this.isInvalid,
112
- 'cpSelect--isDisabled': this.disabled,
113
- 'cpSelect--isLarge': this.isLarge,
114
- }
115
- },
116
- displayErrorMessage() {
117
- return this.isInvalid && this.errorMessage.length
118
- },
119
- },
120
- mounted() {
121
- this.selectReferenceId = randomString()
122
- },
123
- methods: {
124
- handleChange(e) {
125
- this.$emit('update:modelValue', e.target.value)
126
- },
127
- },
41
+ import { randomString, capitalizeFirstLetter } from '@/helpers'
42
+
43
+ interface SelectOption {
44
+ label: string
45
+ value: string | number
46
+ }
47
+
48
+ interface Props {
49
+ autocomplete?: string
50
+ defaultValue?: string
51
+ disabled?: boolean
52
+ errorMessage?: string
53
+ hideDefaultValue?: boolean
54
+ isInvalid?: boolean
55
+ isLarge?: boolean
56
+ label?: string
57
+ modelValue?: string | number
58
+ name?: string
59
+ options: SelectOption[]
60
+ required?: boolean
61
+ }
62
+
63
+ interface Emits {
64
+ (e: 'update:modelValue', value: string): void
128
65
  }
66
+
67
+ const props = withDefaults(defineProps<Props>(), {
68
+ label: '',
69
+ modelValue: '',
70
+ hideDefaultValue: false,
71
+ defaultValue: 'Select an option',
72
+ name: undefined,
73
+ required: false,
74
+ disabled: false,
75
+ autocomplete: 'on',
76
+ isInvalid: false,
77
+ errorMessage: '',
78
+ isLarge: false,
79
+ })
80
+
81
+ const emit = defineEmits<Emits>()
82
+
83
+ const selectReferenceId = ref('')
84
+
85
+ const capitalizedLabel = computed(() => {
86
+ return capitalizeFirstLetter(props.label)
87
+ })
88
+
89
+ const dynamicClasses = computed(() => {
90
+ return {
91
+ 'cpSelect--isInvalid': props.isInvalid,
92
+ 'cpSelect--isDisabled': props.disabled,
93
+ 'cpSelect--isLarge': props.isLarge,
94
+ }
95
+ })
96
+
97
+ const displayErrorMessage = computed(() => {
98
+ return props.isInvalid && props.errorMessage.length
99
+ })
100
+
101
+ const handleChange = (e: Event): void => {
102
+ const target = e.target as HTMLSelectElement
103
+ emit('update:modelValue', target.value)
104
+ }
105
+
106
+ onMounted(() => {
107
+ selectReferenceId.value = randomString()
108
+ })
129
109
  </script>
130
110
 
131
111
  <style lang="scss">
@@ -46,106 +46,104 @@
46
46
  </div>
47
47
  </template>
48
48
 
49
- <script>
49
+ <script setup lang="ts">
50
50
  import { animate } from 'animejs'
51
+ import { ref, computed, nextTick } from 'vue'
51
52
 
52
- export default {
53
- props: {
54
- values: {
55
- type: Array,
56
- default: () => [],
57
- required: true,
58
- },
59
- selectedValue: {
60
- type: Object,
61
- default: () => {},
62
- required: true,
63
- },
64
- isMultiSelect: {
65
- type: Boolean,
66
- default: false,
67
- required: false,
68
- },
69
- hasFilter: {
70
- type: Boolean,
71
- default: false,
72
- required: false,
73
- },
74
- dropdownTitle: {
75
- type: String,
76
- default: 'Select value',
77
- required: false,
78
- },
79
- dropdownFilterPlaceholder: {
80
- type: String,
81
- default: 'Filter...',
82
- required: false,
83
- },
84
- dropdownEmptyViewPlaceholder: {
85
- type: String,
86
- default: 'No option found',
87
- required: false,
88
- },
89
- closeOnSelect: {
90
- type: Boolean,
91
- default: true,
92
- required: false,
93
- },
94
- },
95
- emits: ['update:selectedValue', 'on-close', 'on-filter-change'],
96
- data() {
97
- return {
98
- isDropdownOpen: false,
99
- }
100
- },
101
- computed: {
102
- inputType() {
103
- return (this.isMultiSelect && 'checkbox') || 'radio'
104
- },
105
- },
106
- methods: {
107
- enter() {
108
- animate(this.$refs.dropdownRef, {
109
- scale: [0.8, 1],
110
- opacity: [0, 1],
111
- duration: 200,
112
- ease: 'cubicBezier(0.175, 0.885, 0.32, 1.175)',
113
- })
114
- },
115
- toggleDropdown() {
116
- this.isDropdownOpen = !this.isDropdownOpen
117
-
118
- if (this.isDropdownOpen && this.hasFilter) {
119
- this.$nextTick(() => this.$refs.dropdownFilterRef.focus())
120
- }
121
- },
122
- closeDropdown() {
123
- if (!this.isDropdownOpen) {
124
- return
125
- }
53
+ interface SelectValue {
54
+ label: string
55
+ value: string
56
+ }
126
57
 
127
- this.isDropdownOpen = false
128
- this.resetInputValue()
129
- this.$emit('on-close')
130
- },
131
- onChange(value) {
132
- if (value.value !== this.selectedValue.value) {
133
- this.$emit('update:selectedValue', value)
134
- }
135
- if (this.closeOnSelect) {
136
- this.closeDropdown()
58
+ interface Props {
59
+ closeOnSelect?: boolean
60
+ dropdownEmptyViewPlaceholder?: string
61
+ dropdownFilterPlaceholder?: string
62
+ dropdownTitle?: string
63
+ hasFilter?: boolean
64
+ isMultiSelect?: boolean
65
+ selectedValue: SelectValue
66
+ values: SelectValue[]
67
+ }
68
+
69
+ interface Emits {
70
+ (e: 'update:selectedValue', value: SelectValue): void
71
+ (e: 'onClose'): void
72
+ (e: 'onFilterChange', value: string): void
73
+ }
74
+
75
+ const props = withDefaults(defineProps<Props>(), {
76
+ isMultiSelect: false,
77
+ hasFilter: false,
78
+ dropdownTitle: 'Select value',
79
+ dropdownFilterPlaceholder: 'Filter...',
80
+ dropdownEmptyViewPlaceholder: 'No option found',
81
+ closeOnSelect: true,
82
+ })
83
+
84
+ const emit = defineEmits<Emits>()
85
+
86
+ const isDropdownOpen = ref(false)
87
+ const dropdownRef = ref<HTMLElement>()
88
+ const dropdownFilterRef = ref<HTMLInputElement>()
89
+
90
+ const inputType = computed(() => {
91
+ return props.isMultiSelect ? 'checkbox' : 'radio'
92
+ })
93
+
94
+ const enter = (): void => {
95
+ if (dropdownRef.value) {
96
+ animate(dropdownRef.value, {
97
+ scale: [0.8, 1],
98
+ opacity: [0, 1],
99
+ duration: 200,
100
+ ease: 'cubicBezier(0.175, 0.885, 0.32, 1.175)',
101
+ })
102
+ }
103
+ }
104
+
105
+ const toggleDropdown = (): void => {
106
+ isDropdownOpen.value = !isDropdownOpen.value
107
+
108
+ if (isDropdownOpen.value && props.hasFilter) {
109
+ nextTick(() => {
110
+ if (dropdownFilterRef.value) {
111
+ dropdownFilterRef.value.focus()
137
112
  }
138
- },
139
- updateFilterValue(event) {
140
- this.$emit('on-filter-change', event.target.value)
141
- },
142
- resetInputValue() {
143
- this.$emit('on-filter-change', '')
144
- },
145
- isSelectedValue(value) {
146
- return value === this.selectedValue.value
147
- },
148
- },
113
+ })
114
+ }
115
+ }
116
+
117
+ const closeDropdown = (): void => {
118
+ if (!isDropdownOpen.value) {
119
+ return
120
+ }
121
+
122
+ isDropdownOpen.value = false
123
+ resetInputValue()
124
+ emit('onClose')
125
+ }
126
+
127
+ const onChange = (value: SelectValue): void => {
128
+ if (value.value !== props.selectedValue.value) {
129
+ emit('update:selectedValue', value)
130
+ }
131
+ if (props.closeOnSelect) {
132
+ closeDropdown()
133
+ }
134
+ }
135
+
136
+ const updateFilterValue = (event: Event): void => {
137
+ const target = event.target as HTMLInputElement
138
+ emit('onFilterChange', target.value)
139
+ }
140
+
141
+ const resetInputValue = (): void => {
142
+ emit('onFilterChange', '')
143
+ }
144
+
145
+ const isSelectedValue = (value: string): boolean => {
146
+ return value === props.selectedValue.value
149
147
  }
150
148
  </script>
151
149