vueless 0.0.493 → 0.0.495

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 (32) hide show
  1. package/package.json +1 -1
  2. package/types.ts +37 -0
  3. package/ui.form-calendar/UCalendar.vue +20 -11
  4. package/ui.form-calendar/UCalendarDayView.vue +1 -1
  5. package/ui.form-calendar/UCalendarMonthView.vue +1 -1
  6. package/ui.form-calendar/UCalendarYearView.vue +1 -1
  7. package/ui.form-calendar/config.ts +1 -0
  8. package/ui.form-calendar/constants.ts +0 -6
  9. package/ui.form-calendar/storybook/stories.ts +5 -3
  10. package/ui.form-calendar/types.ts +7 -2
  11. package/ui.form-calendar/useAttrs.ts +1 -1
  12. package/ui.form-calendar/utilDate.ts +2 -2
  13. package/ui.form-date-picker/UDatePicker.vue +18 -16
  14. package/ui.form-date-picker/storybook/stories.ts +6 -4
  15. package/ui.form-date-picker/types.ts +2 -6
  16. package/ui.form-date-picker/useAttrs.ts +1 -1
  17. package/ui.form-date-picker-range/UDatePickerRange.vue +371 -433
  18. package/ui.form-date-picker-range/UDatePickerRangeInputs.vue +67 -76
  19. package/ui.form-date-picker-range/UDatePickerRangePeriodMenu.vue +158 -205
  20. package/ui.form-date-picker-range/{constants.js → constants.ts} +17 -18
  21. package/ui.form-date-picker-range/storybook/Docs.mdx +16 -0
  22. package/ui.form-date-picker-range/storybook/stories.ts +237 -0
  23. package/ui.form-date-picker-range/types.ts +193 -0
  24. package/ui.form-date-picker-range/{useAttrs.js → useAttrs.ts} +21 -5
  25. package/ui.form-date-picker-range/useLocale.ts +65 -0
  26. package/ui.form-date-picker-range/{useUserFormat.js → useUserFormat.ts} +22 -8
  27. package/ui.form-date-picker-range/{utilDateRange.js → utilDateRange.ts} +14 -8
  28. package/ui.form-date-picker-range/{utilValidation.js → utilValidation.ts} +4 -4
  29. package/utils/theme.ts +16 -0
  30. package/web-types.json +158 -52
  31. package/ui.form-date-picker-range/useLocale.js +0 -63
  32. /package/ui.form-date-picker-range/{config.js → config.ts} +0 -0
@@ -1,157 +1,5 @@
1
- <template>
2
- <div v-bind="wrapperAttrs" ref="wrapperRef">
3
- <UInput
4
- v-if="isVariant.input"
5
- :id="elementId"
6
- ref="inputRef"
7
- v-model="userFormatDate"
8
- :size="size"
9
- :label="label"
10
- :label-align="labelAlign"
11
- :disabled="disabled"
12
- :placeholder="placeholder"
13
- :description="description"
14
- :error="error"
15
- readonly
16
- :left-icon="leftIcon"
17
- :right-icon="rightIcon"
18
- v-bind="isShownMenu ? activeInputAttrs : inputAttrs"
19
- @focus="activate"
20
- >
21
- <template #left>
22
- <!-- @slot Use it to add something before the date. -->
23
- <slot name="left" />
24
- </template>
25
-
26
- <template #left-icon>
27
- <!-- @slot Use it to add icon before the date. -->
28
- <slot name="left-icon" />
29
- </template>
30
-
31
- <template #right-icon>
32
- <!--
33
- @slot Use it add an icon after the date.
34
- @binding {string} icon-name
35
- @binding {string} icon-size
36
- -->
37
- <slot name="right-icon" :icon-name="rightIcon" :icon-size="size">
38
- <UIcon :name="rightIcon" :size="size" color="gray" />
39
- </slot>
40
- </template>
41
-
42
- <template #right>
43
- <!-- @slot Use it to add something after the date. -->
44
- <slot name="right" />
45
- </template>
46
- </UInput>
47
-
48
- <div v-if="isVariant.button" v-bind="buttonWrapperAttrs">
49
- <UButton
50
- ref="buttonPrevRef"
51
- square
52
- filled
53
- no-ring
54
- :size="size"
55
- :disabled="disabled"
56
- variant="thirdary"
57
- :left-icon="config.defaults.prevIcon"
58
- v-bind="shiftRangeButtonAttrs"
59
- @click="onClickShiftRange(SHIFT_ACTION.prev)"
60
- />
61
-
62
- <UButton
63
- :id="elementId"
64
- ref="buttonRef"
65
- square
66
- filled
67
- no-ring
68
- :size="size"
69
- :disabled="disabled"
70
- :label="userFormatDate"
71
- variant="thirdary"
72
- v-bind="buttonAttrs"
73
- @click="activate"
74
- />
75
-
76
- <UButton
77
- ref="buttonNextRef"
78
- square
79
- filled
80
- no-ring
81
- :size="size"
82
- :disabled="disabled"
83
- variant="thirdary"
84
- :left-icon="config.defaults.nextIcon"
85
- v-bind="shiftRangeButtonAttrs"
86
- @click="onClickShiftRange(SHIFT_ACTION.next)"
87
- />
88
- </div>
89
-
90
- <Transition v-bind="config.menuTransition">
91
- <div
92
- v-if="isShownMenu"
93
- ref="menuRef"
94
- v-click-outside="[deactivate, clickOutsideOptions]"
95
- tabindex="-1"
96
- v-bind="menuAttrs"
97
- @keydown.esc="deactivate"
98
- >
99
- <UDatePickerRangePeriodMenu
100
- v-model:local-value="localValue"
101
- v-model:active-date="activeDate"
102
- v-model:period-date-list="periodDateList"
103
- v-model:period="period"
104
- :config="config"
105
- :is-period="isPeriod"
106
- :custom-range-button="customRangeButton"
107
- :locale="locale"
108
- :attrs="keysAttrs"
109
- :date-format="dateFormat"
110
- :min-date="minDate"
111
- :max-date="maxDate"
112
- @toggle-menu="isShownMenu = !isShownMenu"
113
- @close-menu="isShownMenu = false"
114
- @click-prev="onClickShiftDatesList(SHIFT_ACTION.prev)"
115
- @click-next="onClickShiftDatesList(SHIFT_ACTION.next)"
116
- />
117
-
118
- <UDatePickerRangeInputs
119
- v-if="isPeriod.ownRange"
120
- v-bind="rangeInputWrapperAttrs"
121
- v-model:local-value="localValue"
122
- v-model:input-range-from-error="inputRangeFromError"
123
- v-model:input-range-to-error="inputRangeToError"
124
- v-model:range-start="rangeStart"
125
- v-model:range-end="rangeEnd"
126
- :range-input-name="rangeInputName"
127
- :locale="locale"
128
- :date-format="dateFormat"
129
- :config="config"
130
- :attrs="keysAttrs"
131
- />
132
-
133
- <div v-if="inputRangeToError || inputRangeFromError" v-bind="rangeInputErrorAttrs">
134
- {{ inputRangeToError || inputRangeFromError }}
135
- </div>
136
-
137
- <UCalendar
138
- v-if="isPeriod.ownRange"
139
- v-model="calendarValue"
140
- :min-date="minDate"
141
- :max-date="maxDate"
142
- v-bind="calendarAttrs"
143
- :date-format="dateFormat"
144
- range
145
- @mouseenter="onMouseoverCalendar"
146
- @input="onInputCalendar"
147
- />
148
- </div>
149
- </Transition>
150
- </div>
151
- </template>
152
-
153
- <script setup>
154
- import { computed, watch, ref, nextTick, provide, useId } from "vue";
1
+ <script setup lang="ts" generic="TModelValue extends RangeDate">
2
+ import { computed, watch, ref, nextTick, provide, useId, useTemplateRef } from "vue";
155
3
  import { getDefault } from "../utils/ui.ts";
156
4
 
157
5
  import UIcon from "../ui.image-icon/UIcon.vue";
@@ -185,205 +33,59 @@ import {
185
33
  getYearDateList,
186
34
  getQuartersDateList,
187
35
  getMonthsDateList,
188
- } from "./utilDateRange.js";
36
+ type DatePeriodRange,
37
+ } from "./utilDateRange.ts";
189
38
 
190
- import useAttrs from "./useAttrs.js";
39
+ import useAttrs from "./useAttrs.ts";
191
40
  import { useAutoPosition } from "../composables/useAutoPosition.ts";
192
- import { useLocale } from "./useLocale.js";
193
- import { useUserFormat } from "./useUserFormat.js";
41
+ import { useLocale } from "./useLocale.ts";
42
+ import { useUserFormat } from "./useUserFormat.ts";
194
43
 
195
- import defaultConfig from "./config.js";
44
+ import defaultConfig from "./config.ts";
196
45
  import {
197
46
  UDatePickerRange,
198
47
  DATE_PICKER_BUTTON_TYPE,
199
48
  DATE_PICKER_INPUT_TYPE,
200
- PERIOD,
201
49
  INPUT_RANGE_FORMAT,
202
- SHIFT_ACTION,
203
- } from "./constants.js";
50
+ ShiftAction,
51
+ Period,
52
+ } from "./constants.ts";
53
+
54
+ import type { Ref, WritableComputedRef } from "vue";
55
+ import type {
56
+ IsDatePeriodOutOfRange,
57
+ ShiftActions,
58
+ SortedLocale,
59
+ UDatePickerRangeProps,
60
+ UDatePickerRangeInputsAttrs,
61
+ UDatePickerRangePeriodMenuAttrs,
62
+ } from "./types.ts";
63
+ import type { RangeDate } from "../ui.form-calendar/types.ts";
64
+ import type { ComponentExposed } from "../types.ts";
204
65
 
205
66
  defineOptions({ inheritAttrs: false });
206
67
 
207
- const props = defineProps({
208
- /**
209
- * Datepicker range value (JavaScript Date objects or strings formatted in given `dateFormat`).
210
- */
211
- modelValue: {
212
- type: Object,
213
- default: () => ({
214
- from: null,
215
- to: null,
216
- }),
217
- },
218
-
219
- /**
220
- * Custom range button.
221
- */
222
- customRangeButton: {
223
- type: Object,
224
- default: () => ({
225
- range: { from: null, to: null },
226
- label: "",
227
- description: "",
228
- }),
229
- },
230
-
231
- /**
232
- * Datepicker open direction on x-axis.
233
- * @values auto, left, right
234
- */
235
- openDirectionX: {
236
- type: String,
237
- default: getDefault(defaultConfig, UDatePickerRange).openDirectionX,
238
- },
239
-
240
- /**
241
- * Datepicker open direction on y-axis.
242
- * @values auto, top, bottom
243
- */
244
- openDirectionY: {
245
- type: String,
246
- default: getDefault(defaultConfig, UDatePickerRange).openDirectionY,
247
- },
248
-
249
- /**
250
- * The variant of the date picker.
251
- * @values button, input
252
- */
253
- variant: {
254
- type: String,
255
- default: getDefault(defaultConfig, UDatePickerRange).variant,
256
- },
257
-
258
- /**
259
- * Min date (JavaScript Date object or string formatted in given `dateFormat`).
260
- */
261
- minDate: {
262
- type: [Date, String],
263
- default: getDefault(defaultConfig, UDatePickerRange).minDate,
264
- },
265
-
266
- /**
267
- * Max date (JavaScript Date object or string formatted in given `dateFormat`).
268
- */
269
- maxDate: {
270
- type: [Date, String],
271
- default: getDefault(defaultConfig, UDatePickerRange).maxDate,
272
- },
273
-
274
- /**
275
- * Date string format.
276
- */
277
- dateFormat: {
278
- type: String,
279
- default: getDefault(defaultConfig, UDatePickerRange).dateFormat,
280
- },
281
-
282
- /**
283
- * User-friendly date format (it will be shown in UI).
284
- */
285
- userDateFormat: {
286
- type: String,
287
- default: getDefault(defaultConfig, UDatePickerRange).userDateFormat,
288
- },
289
-
290
- /**
291
- * Datepicker size.
292
- * @values sm, md, lg
293
- */
294
- size: {
295
- type: String,
296
- default: getDefault(defaultConfig, UDatePickerRange).size,
297
- },
298
-
299
- /**
300
- * Left icon name.
301
- */
302
- leftIcon: {
303
- type: String,
304
- default: "",
305
- },
306
-
307
- /**
308
- * Right icon name.
309
- */
310
- rightIcon: {
311
- type: String,
312
- default: getDefault(defaultConfig, UDatePickerRange).rightIcon,
313
- },
314
-
315
- /**
316
- * Label text for an input type.
317
- */
318
- label: {
319
- type: String,
320
- default: "",
321
- },
322
-
323
- /**
324
- * Label placement.
325
- * @values top, topInside, topWithDesc, left, right
326
- */
327
- labelAlign: {
328
- type: String,
329
- default: getDefault(defaultConfig, UDatePickerRange).labelAlign,
330
- },
331
-
332
- /**
333
- * Input placeholder for an input type.
334
- */
335
- placeholder: {
336
- type: String,
337
- default: "",
338
- },
339
-
340
- /**
341
- * Datepicker description for an input type.
342
- */
343
- description: {
344
- type: String,
345
- default: "",
346
- },
347
-
348
- /**
349
- * Error message for an input type.
350
- */
351
- error: {
352
- type: String,
353
- default: "",
354
- },
355
-
356
- /**
357
- * Disable component.
358
- */
359
- disabled: {
360
- type: Boolean,
361
- default: getDefault(defaultConfig, UDatePickerRange).disabled,
362
- },
363
-
364
- /**
365
- * Unique element id.
366
- */
367
- id: {
368
- type: String,
369
- default: "",
370
- },
371
-
372
- /**
373
- * Component config object.
374
- */
375
- config: {
376
- type: Object,
377
- default: () => ({}),
378
- },
379
-
380
- /**
381
- * Data-test attribute for automated testing.
382
- */
383
- dataTest: {
384
- type: String,
385
- default: "",
386
- },
68
+ type Props = UDatePickerRangeProps<TModelValue>;
69
+ const props = withDefaults(defineProps<Props>(), {
70
+ openDirectionX: getDefault<Props>(defaultConfig, UDatePickerRange).openDirectionX,
71
+ openDirectionY: getDefault<Props>(defaultConfig, UDatePickerRange).openDirectionY,
72
+ variant: getDefault<Props>(defaultConfig, UDatePickerRange).variant,
73
+ dateFormat: getDefault<Props>(defaultConfig, UDatePickerRange).dateFormat,
74
+ userDateFormat: getDefault<Props>(defaultConfig, UDatePickerRange).userDateFormat,
75
+ size: getDefault<Props>(defaultConfig, UDatePickerRange).size,
76
+ leftIcon: getDefault<Props>(defaultConfig, UDatePickerRange).leftIcon,
77
+ rightIcon: getDefault<Props>(defaultConfig, UDatePickerRange).rightIcon,
78
+ labelAlign: getDefault<Props>(defaultConfig, UDatePickerRange).labelAlign,
79
+ label: getDefault<Props>(defaultConfig, UDatePickerRange).label,
80
+ disabled: getDefault<Props>(defaultConfig, UDatePickerRange).disabled,
81
+ customRangeButton: () => ({
82
+ range: { from: null, to: null },
83
+ label: "",
84
+ description: "",
85
+ }),
86
+ id: "",
87
+ dataTest: "",
88
+ config: () => ({}),
387
89
  });
388
90
 
389
91
  const emit = defineEmits([
@@ -394,15 +96,17 @@ const emit = defineEmits([
394
96
  "update:modelValue",
395
97
  ]);
396
98
 
99
+ type UButtonRef = InstanceType<typeof UButton>;
100
+ type UInputRef = InstanceType<typeof UInput>;
101
+
397
102
  const isShownMenu = ref(false);
398
- const wrapperRef = ref(null);
399
- const menuRef = ref(null);
400
- const rangeInputStartRef = ref(null);
401
- const rangeInputEndRef = ref(null);
402
- const buttonRef = ref(null);
403
- const buttonPrevRef = ref(null);
404
- const buttonNextRef = ref(null);
405
- const inputRef = ref(null);
103
+ const wrapperRef = useTemplateRef("wrapper");
104
+ const menuRef = useTemplateRef("menu");
105
+ const buttonRef = useTemplateRef<UButtonRef>("button");
106
+ const buttonPrevRef = useTemplateRef<UButtonRef>("button-prev");
107
+ const buttonNextRef = useTemplateRef<UButtonRef>("button-next");
108
+ const inputRef = useTemplateRef<UInputRef>("input");
109
+ const rageInputs = useTemplateRef<ComponentExposed<typeof UDatePickerRangeInputs>>("range-inputs");
406
110
 
407
111
  const { isTop, isRight, adjustPositionY, adjustPositionX } = useAutoPosition(
408
112
  wrapperRef,
@@ -415,12 +119,12 @@ const { locale, userFormatLocale } = useLocale(props);
415
119
 
416
120
  const isPeriod = computed(() => {
417
121
  return {
418
- week: period.value === PERIOD.week,
419
- month: period.value === PERIOD.month,
420
- quarter: period.value === PERIOD.quarter,
421
- year: period.value === PERIOD.year,
422
- ownRange: period.value === PERIOD.ownRange,
423
- custom: period.value === PERIOD.custom,
122
+ week: period.value === Period.Week,
123
+ month: period.value === Period.Month,
124
+ quarter: period.value === Period.Quarter,
125
+ year: period.value === Period.Year,
126
+ ownRange: period.value === Period.OwnRange,
127
+ custom: period.value === Period.Custom,
424
128
  };
425
129
  });
426
130
 
@@ -428,7 +132,6 @@ const elementId = props.id || useId();
428
132
 
429
133
  const {
430
134
  config,
431
- keysAttrs,
432
135
  wrapperAttrs,
433
136
  calendarAttrs,
434
137
  inputAttrs,
@@ -439,29 +142,65 @@ const {
439
142
  rangeInputWrapperAttrs,
440
143
  rangeInputErrorAttrs,
441
144
  activeInputAttrs,
145
+ rangeInputFirstAttrs,
146
+ rangeInputLastAttrs,
147
+ periodRowAttrs,
148
+ periodButtonAttrs,
149
+ periodButtonActiveAttrs,
150
+ periodDateAttrs,
151
+ periodDateCurrentAttrs,
152
+ periodDateSelectedAttrs,
153
+ periodDateCurrentSelectedAttrs,
154
+ periodDateListAttrs,
155
+ rangeSwitchButtonAttrs,
156
+ rangeSwitchTitleAttrs,
157
+ rangeSwitchWrapperAttrs,
158
+ customRangeDescriptionAttrs,
442
159
  } = useAttrs(props, { isShownMenu, isTop, isRight, isPeriod });
443
160
 
444
161
  const calendarValue = ref(props.modelValue);
445
- const activeDate = ref(
162
+ const activeDate: Ref<string | Date | null> = ref(
446
163
  props.modelValue.from !== null
447
- ? parseDate(props.modelValue.from, props.dateFormat, locale.value)
164
+ ? parseDate<SortedLocale>(props.modelValue.from, props.dateFormat, locale.value)
448
165
  : new Date(),
449
166
  );
450
- const period = ref(PERIOD.ownRange);
167
+ const period = ref(Period.OwnRange);
451
168
  const rangeStart = ref("");
452
169
  const rangeEnd = ref("");
453
170
  const inputRangeFromError = ref("");
454
171
  const inputRangeToError = ref("");
455
- const calendarInnerValue = ref({ from: "", to: "" });
456
- const periodDateList = ref([]);
172
+ const calendarInnerValue: Ref<RangeDate> = ref({ from: "", to: "" });
173
+ const periodDateList: Ref<DatePeriodRange[]> = ref([]);
174
+
175
+ provide<IsDatePeriodOutOfRange>("isDatePeriodOutOfRange", (datePeriod: DatePeriodRange) => {
176
+ return isDatePeriodOutOfRange(datePeriod);
177
+ });
457
178
 
458
- provide("isDatePeriodOutOfRange", (datePeriod) => isDatePeriodOutOfRange(datePeriod));
179
+ const rangeInputsAttrs = computed(() => ({
180
+ rangeInputFirstAttrs,
181
+ rangeInputLastAttrs,
182
+ }));
183
+
184
+ const rangePeriodMenuAttrs = computed(() => ({
185
+ periodRowAttrs,
186
+ periodButtonAttrs,
187
+ periodButtonActiveAttrs,
188
+ periodDateAttrs,
189
+ periodDateCurrentAttrs,
190
+ periodDateSelectedAttrs,
191
+ periodDateCurrentSelectedAttrs,
192
+ periodDateListAttrs,
193
+ rangeSwitchButtonAttrs,
194
+ rangeSwitchTitleAttrs,
195
+ rangeSwitchWrapperAttrs,
196
+ customRangeDescriptionAttrs,
197
+ }));
459
198
 
460
- const localValue = computed({
199
+ const localValue: WritableComputedRef<RangeDate> = computed({
461
200
  get: () => {
462
201
  return {
463
- from: parseDate(props.modelValue.from || null, props.dateFormat, locale.value),
464
- to: parseDate(props.modelValue.to || null, props.dateFormat, locale.value),
202
+ from: parseDate<SortedLocale>(props.modelValue.from || null, props.dateFormat, locale.value),
203
+ to: parseDate<SortedLocale>(props.modelValue.to || null, props.dateFormat, locale.value),
465
204
  };
466
205
  },
467
206
  set: (value) => {
@@ -469,8 +208,12 @@ const localValue = computed({
469
208
  emit("update:modelValue", value);
470
209
  }
471
210
 
472
- const parsedDateFrom = parseDate(value.from || null, props.dateFormat, locale.value);
473
- const parsedDateTo = parseDate(value.to || null, props.dateFormat, locale.value);
211
+ const parsedDateFrom = parseDate<SortedLocale>(
212
+ value.from || null,
213
+ props.dateFormat,
214
+ locale.value,
215
+ );
216
+ const parsedDateTo = parseDate<SortedLocale>(value.to || null, props.dateFormat, locale.value);
474
217
 
475
218
  if (value.from && value.to && props.dateFormat) {
476
219
  const newValue = {
@@ -494,14 +237,14 @@ const isVariant = computed(() => ({
494
237
 
495
238
  const clickOutsideOptions = computed(() => {
496
239
  if (isVariant.value.input) {
497
- return { ignore: [inputRef.value.inputRef] };
240
+ return { ignore: [inputRef.value?.inputRef] };
498
241
  }
499
242
 
500
243
  return {
501
244
  ignore: [
502
- buttonRef.value.buttonRef,
503
- buttonPrevRef.value.buttonRef,
504
- buttonNextRef.value.buttonRef,
245
+ buttonRef.value?.buttonRef,
246
+ buttonPrevRef.value?.buttonRef,
247
+ buttonNextRef.value?.buttonRef,
505
248
  ],
506
249
  };
507
250
  });
@@ -509,6 +252,7 @@ const clickOutsideOptions = computed(() => {
509
252
  const { userFormatDate } = useUserFormat(
510
253
  localValue,
511
254
  userFormatLocale,
255
+ props.dateFormat,
512
256
  isPeriod,
513
257
  locale,
514
258
  props.userDateFormat,
@@ -563,11 +307,13 @@ watch(period, () => {
563
307
  }
564
308
 
565
309
  if (isDate && props.dateFormat) {
566
- activeDate.value = isDate ? parseDate(localValue.value.from, locale.value) : new Date();
310
+ activeDate.value = isDate
311
+ ? parseDate(localValue.value.from, props.dateFormat, locale.value)
312
+ : new Date();
567
313
  }
568
314
  });
569
315
 
570
- function isDatePeriodOutOfRange(datePeriod) {
316
+ function isDatePeriodOutOfRange(datePeriod: DatePeriodRange) {
571
317
  return (
572
318
  dateIsOutOfRange(
573
319
  datePeriod.startRange,
@@ -586,7 +332,7 @@ function activate() {
586
332
  adjustPositionY();
587
333
  adjustPositionX();
588
334
 
589
- menuRef.value.focus();
335
+ menuRef.value?.focus();
590
336
  });
591
337
  }
592
338
 
@@ -597,8 +343,10 @@ function deactivate() {
597
343
  setDefaultPeriodForButton();
598
344
 
599
345
  function setDefaultPeriodForButton() {
600
- const from = props.modelValue.from || new Date();
601
- const to = props.modelValue.to || new Date();
346
+ const { modelValue, dateFormat } = props;
347
+
348
+ const from = parseDate<SortedLocale>(modelValue.from, dateFormat, locale.value) || new Date();
349
+ const to = parseDate<SortedLocale>(modelValue.to, dateFormat, locale.value) || new Date();
602
350
 
603
351
  const customFrom = props.customRangeButton.range.from || new Date();
604
352
  const customTo = props.customRangeButton.range.to || new Date();
@@ -616,113 +364,134 @@ function setDefaultPeriodForButton() {
616
364
  String(from) === String(getStartOfYear(from)) && String(to) === String(getEndOfYear(to));
617
365
  const isCustomPeriod = String(from) === String(customFrom) && String(to) === String(customTo);
618
366
 
619
- if (!props.modelValue.from && !props.modelValue.to) {
620
- period.value = PERIOD.ownRange;
367
+ if (!modelValue.from && !modelValue.to) {
368
+ period.value = Period.OwnRange;
621
369
  } else if (isYearPeriod) {
622
- period.value = PERIOD.year;
370
+ period.value = Period.Year;
623
371
  } else if (isMonthPeriod) {
624
- period.value = PERIOD.month;
372
+ period.value = Period.Month;
625
373
  } else if (isQuarterPeriod) {
626
- period.value = PERIOD.quarter;
374
+ period.value = Period.Quarter;
627
375
  } else if (isWeekPeriod) {
628
- period.value = PERIOD.week;
376
+ period.value = Period.Week;
629
377
  } else if (isCustomPeriod) {
630
- period.value = PERIOD.custom;
378
+ period.value = Period.Custom;
631
379
  } else {
632
- period.value = PERIOD.ownRange;
380
+ period.value = Period.OwnRange;
633
381
  }
634
382
  }
635
383
 
636
- function onClickShiftDatesList(action) {
637
- const defaultRange = action === SHIFT_ACTION.prev ? -1 : 1;
638
- const yearRange = action === SHIFT_ACTION.prev ? -12 : 12;
384
+ function onClickShiftDatesList(action: ShiftActions) {
385
+ const defaultRange = action === ShiftAction.Prev ? -1 : 1;
386
+ const yearRange = action === ShiftAction.Prev ? -12 : 12;
387
+ const parsedActiveDate = parseDate(activeDate.value, props.dateFormat, locale.value);
639
388
 
640
- if (isPeriod.value.week) {
641
- activeDate.value = addMonths(activeDate.value, defaultRange);
389
+ if (isPeriod.value.week && parsedActiveDate) {
390
+ activeDate.value = addMonths(parsedActiveDate, defaultRange);
642
391
  periodDateList.value = getWeekDateList(activeDate.value, locale.value.months.shorthand);
643
392
  }
644
393
 
645
- if (isPeriod.value.month) {
646
- activeDate.value = addYears(activeDate.value, defaultRange);
394
+ if (isPeriod.value.month && parsedActiveDate) {
395
+ activeDate.value = addYears(parsedActiveDate, defaultRange);
647
396
  periodDateList.value = getMonthsDateList(activeDate.value, locale.value.months.longhand);
648
397
  }
649
398
 
650
- if (isPeriod.value.quarter) {
651
- activeDate.value = addYears(activeDate.value, defaultRange);
399
+ if (isPeriod.value.quarter && parsedActiveDate) {
400
+ activeDate.value = addYears(parsedActiveDate, defaultRange);
652
401
  periodDateList.value = getQuartersDateList(activeDate.value, locale.value.quarter);
653
402
  }
654
403
 
655
- if (isPeriod.value.year) {
656
- activeDate.value = addYears(activeDate.value, yearRange);
404
+ if (isPeriod.value.year && parsedActiveDate) {
405
+ activeDate.value = addYears(parsedActiveDate, yearRange);
657
406
  periodDateList.value = getYearDateList(activeDate.value);
658
407
  }
659
408
  }
660
409
 
661
- function shiftRangeNext(to, from, daysDifference) {
410
+ function shiftRangeNext(to: Date, from: Date, daysDifference: number) {
662
411
  if (isPeriod.value.ownRange) {
663
412
  const nextDate = {
664
- to: addDays(to, daysDifference),
665
- from: addDays(from, daysDifference),
413
+ title: "",
414
+ startRange: addDays(to, daysDifference),
415
+ endRange: addDays(from, daysDifference),
666
416
  };
667
417
 
668
418
  if (isDatePeriodOutOfRange(nextDate)) return;
669
419
 
670
- localValue.value = nextDate;
420
+ localValue.value = {
421
+ from: nextDate.startRange,
422
+ to: nextDate.startRange,
423
+ };
671
424
 
672
425
  return;
673
426
  }
674
427
 
675
- let nextDate = periodDateList.value.find((item) => item.endRange > localValue.value.to);
428
+ let nextDate = periodDateList.value.find(
429
+ (item) => localValue.value.to && item.endRange > localValue.value.to,
430
+ );
676
431
 
677
432
  if (!nextDate) {
678
- onClickShiftDatesList(SHIFT_ACTION.next);
433
+ onClickShiftDatesList(ShiftAction.Next);
679
434
 
680
- nextDate = periodDateList.value.find((item) => item.endRange > localValue.value.to);
435
+ nextDate = periodDateList.value.find(
436
+ (item) => localValue.value.to && item.endRange > localValue.value.to,
437
+ );
681
438
  }
682
439
 
683
- if (isDatePeriodOutOfRange(nextDate)) return;
440
+ if (nextDate && isDatePeriodOutOfRange(nextDate)) return;
684
441
 
685
- localValue.value = {
686
- from: nextDate.startRange,
687
- to: nextDate.endRange,
688
- };
442
+ if (nextDate) {
443
+ localValue.value = {
444
+ from: nextDate.startRange,
445
+ to: nextDate.endRange,
446
+ };
447
+ }
689
448
  }
690
449
 
691
- function shiftRangePrev(to, from, daysDifference) {
450
+ function shiftRangePrev(to: Date, from: Date, daysDifference: number) {
692
451
  if (isPeriod.value.ownRange) {
693
452
  const previousDate = {
694
- to: addDays(to, daysDifference * -1),
695
- from: addDays(from, daysDifference * -1),
453
+ title: "",
454
+ startRange: addDays(to, daysDifference * -1),
455
+ endRange: addDays(from, daysDifference * -1),
696
456
  };
697
457
 
698
458
  if (isDatePeriodOutOfRange(previousDate)) return;
699
459
 
700
- localValue.value = previousDate;
460
+ localValue.value = {
461
+ from: previousDate.startRange,
462
+ to: previousDate.startRange,
463
+ };
701
464
  } else {
702
465
  const reverseDatesList = [...periodDateList.value].reverse();
703
466
 
704
- let previousDate = reverseDatesList.find((item) => item.endRange < localValue.value.to);
467
+ let previousDate = reverseDatesList.find(
468
+ (item) => localValue.value.to && item.endRange < localValue.value.to,
469
+ );
705
470
 
706
471
  if (!previousDate) {
707
- onClickShiftDatesList(SHIFT_ACTION.prev);
472
+ onClickShiftDatesList(ShiftAction.Prev);
708
473
 
709
474
  const reverseDatesList = [...periodDateList.value].reverse();
710
475
 
711
- previousDate = reverseDatesList.find((item) => item.endRange < localValue.value.to);
476
+ previousDate = reverseDatesList.find(
477
+ (item) => localValue.value.to && item.endRange < localValue.value.to,
478
+ );
712
479
  }
713
480
 
714
- if (isDatePeriodOutOfRange(previousDate)) return;
481
+ if (previousDate && isDatePeriodOutOfRange(previousDate)) return;
715
482
 
716
- localValue.value = {
717
- from: previousDate.startRange,
718
- to: previousDate.endRange,
719
- };
483
+ if (previousDate) {
484
+ localValue.value = {
485
+ from: previousDate.startRange,
486
+ to: previousDate.endRange,
487
+ };
488
+ }
720
489
  }
721
490
  }
722
491
 
723
- function onClickShiftRange(action) {
492
+ function onClickShiftRange(action: ShiftActions) {
724
493
  if (isPeriod.value.custom) {
725
- period.value = PERIOD.ownRange;
494
+ period.value = Period.OwnRange;
726
495
  }
727
496
 
728
497
  const millisecondsPerSecond = 1000;
@@ -733,39 +502,208 @@ function onClickShiftRange(action) {
733
502
  const millisecondsPerDay =
734
503
  millisecondsPerSecond * secondsPerMinute * minutesPerHour * hoursPerDay;
735
504
 
736
- const from = localValue.value.from;
737
- const to = localValue.value.to ? localValue.value.to : addDays(from, 1);
505
+ const from = parseDate<SortedLocale>(localValue.value.from, props.dateFormat, locale.value);
506
+ let to = parseDate<SortedLocale>(localValue.value.to, props.dateFormat, locale.value);
507
+
508
+ if (!from) return;
509
+ to = to || addDays(from, 1);
510
+
738
511
  const daysDifference = Math.ceil(Math.abs(getDatesDifference(from, to)) / millisecondsPerDay);
739
512
 
740
- action === SHIFT_ACTION.next
513
+ action === ShiftAction.Next
741
514
  ? shiftRangeNext(to, from, daysDifference)
742
515
  : shiftRangePrev(to, from, daysDifference);
743
516
  }
744
517
 
745
518
  function onMouseoverCalendar() {
746
- const isRangeInputFocus = document.activeElement.name === rangeInputName.value;
747
-
748
- if (isRangeInputFocus || !rangeInputStartRef.value || !rangeInputEndRef.value) return;
519
+ const isInputActiveElement = document.activeElement instanceof HTMLInputElement;
520
+ const activeElement = isInputActiveElement
521
+ ? (document.activeElement as HTMLInputElement)
522
+ : undefined;
523
+ const isRangeInputFocus = activeElement?.name === rangeInputName.value;
524
+
525
+ if (
526
+ isRangeInputFocus ||
527
+ !rageInputs.value?.rangeInputStartRef ||
528
+ !rageInputs.value?.rangeInputEndRef
529
+ ) {
530
+ return;
531
+ }
749
532
 
750
533
  const hasValues =
751
534
  calendarInnerValue.value.from && calendarInnerValue.value.to && !inputRangeToError.value;
752
535
  const hasOnlyFromValue =
753
536
  calendarInnerValue.value.from && !calendarInnerValue.value.to && !inputRangeFromError.value;
754
537
 
755
- if (hasValues || !rangeStart.value) {
756
- rangeInputStartRef.value.inputRef.focus();
538
+ if ((hasValues || !rangeStart.value) && rageInputs.value?.rangeInputStartRef?.inputRef) {
539
+ (rageInputs.value.rangeInputStartRef.inputRef as HTMLInputElement).focus();
757
540
 
758
541
  return;
759
542
  }
760
543
 
761
- if (hasOnlyFromValue) {
762
- rangeInputEndRef.value.inputRef.focus();
544
+ if (hasOnlyFromValue && rageInputs.value?.rangeInputEndRef?.inputRef) {
545
+ (rageInputs.value.rangeInputEndRef.inputRef as HTMLInputElement).focus();
763
546
 
764
547
  return;
765
548
  }
766
549
  }
767
550
 
768
- function onInputCalendar(value) {
551
+ function onInputCalendar(value: RangeDate) {
769
552
  calendarInnerValue.value = value;
770
553
  }
771
554
  </script>
555
+
556
+ <template>
557
+ <div v-bind="wrapperAttrs" ref="wrapper">
558
+ <UInput
559
+ v-if="isVariant.input"
560
+ :id="elementId"
561
+ ref="inputRef"
562
+ v-model="userFormatDate"
563
+ :size="size"
564
+ :label="label"
565
+ :label-align="labelAlign"
566
+ :disabled="disabled"
567
+ :placeholder="placeholder"
568
+ :description="description"
569
+ :error="error"
570
+ readonly
571
+ :left-icon="leftIcon"
572
+ :right-icon="rightIcon"
573
+ v-bind="isShownMenu ? activeInputAttrs : inputAttrs"
574
+ @focus="activate"
575
+ >
576
+ <template #left>
577
+ <!-- @slot Use it to add something before the date. -->
578
+ <slot name="left" />
579
+ </template>
580
+
581
+ <template #left-icon>
582
+ <!-- @slot Use it to add icon before the date. -->
583
+ <slot name="left-icon" />
584
+ </template>
585
+
586
+ <template #right-icon>
587
+ <!--
588
+ @slot Use it add an icon after the date.
589
+ @binding {string} icon-name
590
+ @binding {string} icon-size
591
+ -->
592
+ <slot name="right-icon" :icon-name="rightIcon" :icon-size="size">
593
+ <UIcon :name="rightIcon" :size="size" color="gray" />
594
+ </slot>
595
+ </template>
596
+
597
+ <template #right>
598
+ <!-- @slot Use it to add something after the date. -->
599
+ <slot name="right" />
600
+ </template>
601
+ </UInput>
602
+
603
+ <div v-if="isVariant.button" v-bind="buttonWrapperAttrs">
604
+ <UButton
605
+ ref="button-prev"
606
+ square
607
+ filled
608
+ no-ring
609
+ :size="size"
610
+ :disabled="disabled"
611
+ variant="thirdary"
612
+ :left-icon="config.defaults?.prevIcon"
613
+ v-bind="shiftRangeButtonAttrs"
614
+ @click="onClickShiftRange(ShiftAction.Prev)"
615
+ />
616
+
617
+ <UButton
618
+ :id="elementId"
619
+ ref="button"
620
+ square
621
+ filled
622
+ no-ring
623
+ :size="size"
624
+ :disabled="disabled"
625
+ :label="userFormatDate"
626
+ variant="thirdary"
627
+ v-bind="buttonAttrs"
628
+ @click="activate"
629
+ />
630
+
631
+ <UButton
632
+ ref="button-next"
633
+ square
634
+ filled
635
+ no-ring
636
+ :size="size"
637
+ :disabled="disabled"
638
+ variant="thirdary"
639
+ :left-icon="config.defaults?.nextIcon"
640
+ v-bind="shiftRangeButtonAttrs"
641
+ @click="onClickShiftRange(ShiftAction.Next)"
642
+ />
643
+ </div>
644
+
645
+ <Transition v-bind="config.menuTransition">
646
+ <div
647
+ v-if="isShownMenu"
648
+ ref="menu"
649
+ v-click-outside="[deactivate, clickOutsideOptions]"
650
+ tabindex="-1"
651
+ v-bind="menuAttrs"
652
+ @keydown.esc="deactivate"
653
+ >
654
+ <UDatePickerRangePeriodMenu
655
+ v-model:local-value="localValue"
656
+ v-model:active-date="activeDate"
657
+ v-model:period-date-list="periodDateList"
658
+ v-model:period="period"
659
+ :config="config"
660
+ :is-period="isPeriod"
661
+ :custom-range-button="customRangeButton"
662
+ :locale="locale"
663
+ :date-format="dateFormat"
664
+ :min-date="minDate"
665
+ :max-date="maxDate"
666
+ :attrs="rangePeriodMenuAttrs as unknown as UDatePickerRangePeriodMenuAttrs"
667
+ @toggle-menu="isShownMenu = !isShownMenu"
668
+ @close-menu="isShownMenu = false"
669
+ @click-prev="onClickShiftDatesList(ShiftAction.Prev)"
670
+ @click-next="onClickShiftDatesList(ShiftAction.Next)"
671
+ />
672
+
673
+ <UDatePickerRangeInputs
674
+ v-if="isPeriod.ownRange"
675
+ v-bind="rangeInputWrapperAttrs"
676
+ ref="range-inputs"
677
+ v-model:local-value="localValue"
678
+ v-model:input-range-from-error="inputRangeFromError"
679
+ v-model:input-range-to-error="inputRangeToError"
680
+ v-model:range-start="rangeStart"
681
+ v-model:range-end="rangeEnd"
682
+ :range-input-name="rangeInputName"
683
+ :locale="locale"
684
+ :max-date="maxDate"
685
+ :min-date="minDate"
686
+ :date-format="dateFormat"
687
+ :config="config"
688
+ :attrs="rangeInputsAttrs as unknown as UDatePickerRangeInputsAttrs"
689
+ />
690
+
691
+ <div v-if="inputRangeToError || inputRangeFromError" v-bind="rangeInputErrorAttrs">
692
+ {{ inputRangeToError || inputRangeFromError }}
693
+ </div>
694
+
695
+ <UCalendar
696
+ v-if="isPeriod.ownRange"
697
+ v-model="calendarValue"
698
+ :min-date="minDate"
699
+ :max-date="maxDate"
700
+ v-bind="calendarAttrs"
701
+ :date-format="dateFormat"
702
+ range
703
+ @mouseenter="onMouseoverCalendar"
704
+ @input="onInputCalendar"
705
+ />
706
+ </div>
707
+ </Transition>
708
+ </div>
709
+ </template>