@it-enterprise/forcebpm-ui-kit 1.0.2-beta.21 → 1.0.2-beta.22

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.
@@ -0,0 +1,337 @@
1
+ <script setup>
2
+ // FMenuDatePicker
3
+ import { ref, computed, watch, nextTick } from 'vue'
4
+ import moment from 'moment'
5
+ import FDatePicker from './FDatePicker.vue'
6
+ import FTextFieldDate from './FTextFieldDate.vue'
7
+
8
+ const props = defineProps({
9
+ title: {
10
+ type: String,
11
+ default: null,
12
+ validator(value, props) {
13
+ if (!props.isInput && !props.isRange) {
14
+ console.warn('title cannot be used with isInput=false and isRange=false')
15
+ return false
16
+ }
17
+ return true
18
+ }
19
+ },
20
+ prependText: {
21
+ type: String,
22
+ default: null
23
+ },
24
+ type: {
25
+ type: String,
26
+ default: 'date',
27
+ validator: value => ['date', 'datetime'].includes(value)
28
+ },
29
+ color: {
30
+ type: String,
31
+ default: 'secondary'
32
+ },
33
+ disabled: {
34
+ type: Boolean,
35
+ default: false
36
+ },
37
+ isRange: {
38
+ type: Boolean,
39
+ default: false
40
+ },
41
+ isInput: {
42
+ type: Boolean,
43
+ default: true
44
+ },
45
+ clearable: {
46
+ type: Boolean,
47
+ default: false
48
+ },
49
+ isTodayMin: {
50
+ type: Boolean,
51
+ default: false
52
+ },
53
+ menu: {
54
+ type: Boolean,
55
+ default: false
56
+ },
57
+ menuProps: {
58
+ type: Object,
59
+ default: () => ({
60
+ top: true
61
+ })
62
+ },
63
+ allowedDates: {
64
+ type: Function,
65
+ default: () => true
66
+ }
67
+ })
68
+
69
+ const modelValue = defineModel({
70
+ type: [String, Date, Object],
71
+ default: ''
72
+ })
73
+
74
+ const localMenu = ref(props.menu)
75
+ const textDate = ref(null)
76
+ const textFromDate = ref(null)
77
+ const textToDate = ref(null)
78
+ const date = ref(props.isRange ? { from: null, to: null } : null)
79
+ const FORMAT_DATE = props.type === 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm'
80
+
81
+ const emit = defineEmits(['save', 'cancel', 'update:menu'])
82
+
83
+ const isInputDate = computed(() => {
84
+ return props.title ? Boolean(textDate.value && date.value) : true
85
+ })
86
+
87
+ const isInputRangeDate = computed(() => {
88
+ return props.title ? Boolean(textFromDate.value && textToDate.value && date.value) : true
89
+ })
90
+
91
+ const isValidDate = computed(() => {
92
+ return props.isRange ? moment(textFromDate.value).isValid() && moment(textToDate.value).isValid() : moment(textDate.value).isValid()
93
+ })
94
+
95
+ const initDate = () => {
96
+ if (
97
+ modelValue.value &&
98
+ (moment.isMoment(modelValue.value) ||
99
+ ((typeof modelValue.value === 'string' || modelValue.value instanceof Date) && moment(modelValue.value).isValid()))
100
+ ) {
101
+ const formattedValue = moment(modelValue.value).format(FORMAT_DATE)
102
+ textDate.value = formattedValue
103
+ date.value = formattedValue
104
+ return
105
+ }
106
+
107
+ if (modelValue.value && props.isRange && typeof modelValue.value === 'object' && modelValue.value.from && modelValue.value.to) {
108
+ date.value = {
109
+ from: moment(modelValue.value.from).isValid() ? moment(modelValue.value.from).format(FORMAT_DATE) : modelValue.value.from,
110
+ to: moment(modelValue.value.to).isValid() ? moment(modelValue.value.to).format(FORMAT_DATE) : modelValue.value.to
111
+ }
112
+ textFromDate.value = date.value.from
113
+ textToDate.value = date.value.to
114
+ } else {
115
+ textDate.value = null
116
+ textFromDate.value = null
117
+ textToDate.value = null
118
+ date.value = props.isRange ? { from: null, to: null } : null
119
+ }
120
+ }
121
+
122
+ const menuAllowedDates = val => {
123
+ if (props.isTodayMin) {
124
+ return moment(val).isSameOrAfter(moment(), 'day')
125
+ } else {
126
+ return props.allowedDates(val)
127
+ }
128
+ }
129
+ const rangeFromAllowedDates = val => {
130
+ return moment(val).isSameOrBefore(moment(date.value.to), 'day')
131
+ }
132
+ const rangeToAllowedDates = val => {
133
+ return moment(val).isSameOrAfter(moment(date.value.from), 'day')
134
+ }
135
+
136
+ const textFieldFromDateHandler = value => {
137
+ textFromDate.value = value
138
+ if (date.value) {
139
+ date.value.from = value || null
140
+ modelValue.value = date.value
141
+ }
142
+ }
143
+
144
+ const textFieldToDateHandler = value => {
145
+ textToDate.value = value
146
+ if (date.value) {
147
+ date.value.to = value || null
148
+ modelValue.value = date.value
149
+ }
150
+ }
151
+
152
+ const textFieldDateHandler = value => {
153
+ textDate.value = value
154
+ date.value = value || null
155
+ modelValue.value = date.value
156
+ }
157
+
158
+ const clearDate = () => {
159
+ textFromDate.value = null
160
+ textToDate.value = null
161
+ textDate.value = null
162
+ date.value = null
163
+ modelValue.value = date.value
164
+ }
165
+
166
+ const cancel = () => {
167
+ initDate()
168
+ localMenu.value = false
169
+ }
170
+
171
+ const menuHandler = val => {
172
+ emit('update:menu', val)
173
+
174
+ if (val === false) {
175
+ nextTick(() => {
176
+ cancel()
177
+ })
178
+ }
179
+ }
180
+
181
+ const save = () => {
182
+ localMenu.value = false
183
+
184
+ if (props.isRange) {
185
+ if (date.value && date.value.from && date.value.to) {
186
+ modelValue.value = date.value
187
+ emit('save', date.value)
188
+ }
189
+ } else {
190
+ if (date.value) {
191
+ const formattedValue = typeof date.value === 'string' ? date.value : moment(date.value).format(FORMAT_DATE)
192
+ modelValue.value = formattedValue
193
+ emit('save', formattedValue)
194
+ }
195
+ }
196
+ }
197
+
198
+ watch(modelValue, initDate, { immediate: true })
199
+
200
+ watch(
201
+ () => props.menu,
202
+ newVal => {
203
+ localMenu.value = newVal
204
+ }
205
+ )
206
+ </script>
207
+
208
+ <template>
209
+ <div class="f-menu-date-picker d-flex align-center">
210
+ <template v-if="isInput">
211
+ <div v-if="isRange && isInputRangeDate" class="d-flex align-center f-menu-date-picker-range-input">
212
+ <!-- From input date -->
213
+ <div class="d-flex align-center">
214
+ <FTextFieldDate
215
+ v-model="textFromDate"
216
+ :type="type"
217
+ :color="color"
218
+ :disabled="disabled"
219
+ :allowed-dates="rangeFromAllowedDates"
220
+ @blur="textFieldFromDateHandler"
221
+ />
222
+ </div>
223
+
224
+ <FIcon icon="ctx-arrow-next" :color="color" class="mx-1" />
225
+
226
+ <!-- To input date -->
227
+ <div class="d-flex align-center">
228
+ <FTextFieldDate
229
+ v-model="textToDate"
230
+ :type="type"
231
+ :color="color"
232
+ :disabled="disabled"
233
+ :allowed-dates="rangeToAllowedDates"
234
+ @blur="textFieldToDateHandler"
235
+ />
236
+ </div>
237
+ </div>
238
+
239
+ <template v-else-if="isInputDate">
240
+ <!-- Prepend text -->
241
+ <span v-if="prependText" :class="`text-${color}`" class="f-menu-date-picker-prepend-text mr-1">{{ prependText }}:</span>
242
+
243
+ <!-- Input date -->
244
+ <FTextFieldDate
245
+ v-model="textDate"
246
+ :type="type"
247
+ :color="color"
248
+ :disabled="disabled"
249
+ :allowed-dates="menuAllowedDates"
250
+ @blur="textFieldDateHandler"
251
+ />
252
+ </template>
253
+ </template>
254
+
255
+ <!-- Select date -->
256
+ <v-menu
257
+ v-model="localMenu"
258
+ v-bind="menuProps"
259
+ persistent
260
+ min-width="auto"
261
+ offset="0, -6"
262
+ location="bottom right"
263
+ content-class="f-menu-date-picker-content"
264
+ :disabled="disabled"
265
+ :close-on-content-click="false"
266
+ @update:model-value="menuHandler"
267
+ >
268
+ <template #activator="{ props: propsMenu }">
269
+ <div v-bind="propsMenu" class="f-menu-date-picker-activator">
270
+ <span v-if="!isInputDate && !isInputRangeDate" class="d-flex align-center">
271
+ <!-- Prepend text -->
272
+ <span v-if="prependText" :class="`text-${color}`" class="f-menu-date-picker-prepend-text mr-1">{{ prependText }}:</span>
273
+ <!-- Title -->
274
+ <span :class="disabled ? 'is-disabled' : `text-${color}`" class="f-menu-date-picker-title">{{ title }}</span>
275
+ </span>
276
+
277
+ <!-- Icon -->
278
+ <v-tooltip location="top" offset="8" :disabled="disabled" :text="$t('tooltip.calendar')">
279
+ <template #activator="{ props: propsTooltip }">
280
+ <FIcon icon="calendar" :color="color" class="ml-1" :class="disabled ? 'cursor-default' : 'cursor-pointer'" v-bind="propsTooltip" />
281
+ </template>
282
+ </v-tooltip>
283
+ </div>
284
+ </template>
285
+
286
+ <FDatePicker
287
+ v-model="date"
288
+ is-actions
289
+ :is-range="isRange"
290
+ :type="type"
291
+ :color="color"
292
+ :allowed-dates="menuAllowedDates"
293
+ @save="save"
294
+ @cancel="cancel"
295
+ />
296
+ </v-menu>
297
+
298
+ <!-- Clear date -->
299
+ <v-tooltip v-if="clearable && isValidDate && !disabled" location="top" offset="12" :text="$t('tooltip.clearDate')">
300
+ <template #activator="{ props: propsClear }">
301
+ <v-btn v-bind="propsClear" variant="text" size="16" class="ml-1 pt-1 f-menu-date-picker-clear-btn" @click="clearDate">
302
+ <FIcon icon="times" color="secondary" size="12" />
303
+ </v-btn>
304
+ </template>
305
+ </v-tooltip>
306
+ </div>
307
+ </template>
308
+
309
+ <style lang="scss" scoped>
310
+ .f-menu-date-picker {
311
+ .f-menu-date-picker-prepend-text {
312
+ font-size: 1.1em;
313
+ }
314
+ .f-menu-date-picker-activator {
315
+ display: flex;
316
+ position: relative;
317
+ bottom: 2px;
318
+ .f-menu-date-picker-title {
319
+ font-size: 1.1em;
320
+ position: relative;
321
+ &::after {
322
+ content: '';
323
+ display: block;
324
+ position: absolute;
325
+ bottom: 0;
326
+ min-height: 0.5px;
327
+ height: 0.5px;
328
+ width: 100%;
329
+ background: currentColor;
330
+ }
331
+ &.is-disabled::after {
332
+ content: none;
333
+ }
334
+ }
335
+ }
336
+ }
337
+ </style>