goodteditor-ui 1.0.9 → 1.0.12

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 (75) hide show
  1. package/.eslintrc.js +7 -7
  2. package/.idea/codeStyles/Project.xml +51 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/goodt-ui.iml +12 -0
  5. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  6. package/.idea/modules.xml +8 -0
  7. package/.idea/vcs.xml +6 -0
  8. package/.prettierrc +14 -14
  9. package/README.md +35 -35
  10. package/babel.config.js +5 -5
  11. package/index.js +51 -47
  12. package/jsconfig.json +13 -13
  13. package/package.json +57 -57
  14. package/src/App.vue +36 -36
  15. package/src/components/ui/Avatar.md +68 -0
  16. package/src/components/ui/Avatar.vue +177 -0
  17. package/src/components/ui/Badge.md +20 -20
  18. package/src/components/ui/Badge.vue +75 -75
  19. package/src/components/ui/Collapse.md +90 -90
  20. package/src/components/ui/Collapse.vue +86 -86
  21. package/src/components/ui/ColorPicker/Alpha.vue +114 -114
  22. package/src/components/ui/ColorPicker/Colors.vue +117 -117
  23. package/src/components/ui/ColorPicker/Hue.vue +113 -113
  24. package/src/components/ui/ColorPicker/Preview.vue +55 -55
  25. package/src/components/ui/ColorPicker/Saturation.vue +123 -123
  26. package/src/components/ui/ColorPicker/mixin.js +105 -105
  27. package/src/components/ui/ColorPicker.md +17 -17
  28. package/src/components/ui/ColorPicker.vue +314 -314
  29. package/src/components/ui/Datalist.md +41 -41
  30. package/src/components/ui/Datalist.vue +157 -157
  31. package/src/components/ui/DatePicker.md +168 -168
  32. package/src/components/ui/DatePicker.vue +527 -527
  33. package/src/components/ui/FileSelector.md +105 -105
  34. package/src/components/ui/FileSelector.vue +82 -82
  35. package/src/components/ui/Grid.md +130 -130
  36. package/src/components/ui/Grid.vue +92 -92
  37. package/src/components/ui/Image.md +59 -59
  38. package/src/components/ui/Image.vue +57 -57
  39. package/src/components/ui/InputAutocomplete.md +115 -115
  40. package/src/components/ui/InputAutocomplete.vue +341 -341
  41. package/src/components/ui/InputColorPicker.md +51 -51
  42. package/src/components/ui/InputColorPicker.vue +151 -151
  43. package/src/components/ui/InputDatePicker.md +121 -121
  44. package/src/components/ui/InputDatePicker.vue +310 -310
  45. package/src/components/ui/InputTags.md +51 -51
  46. package/src/components/ui/InputTags.vue +184 -184
  47. package/src/components/ui/InputTimePicker.md +25 -25
  48. package/src/components/ui/InputTimePicker.vue +253 -253
  49. package/src/components/ui/InputUnits.md +20 -20
  50. package/src/components/ui/InputUnits.vue +257 -257
  51. package/src/components/ui/Lazy.md +37 -37
  52. package/src/components/ui/Lazy.vue +92 -92
  53. package/src/components/ui/Pagination.md +74 -74
  54. package/src/components/ui/Pagination.vue +138 -138
  55. package/src/components/ui/Paginator.md +34 -34
  56. package/src/components/ui/Paginator.vue +83 -83
  57. package/src/components/ui/Popover.md +34 -34
  58. package/src/components/ui/Popover.vue +209 -209
  59. package/src/components/ui/Popup.md +59 -59
  60. package/src/components/ui/Popup.vue +150 -150
  61. package/src/components/ui/ResponsiveContainer.md +58 -0
  62. package/src/components/ui/ResponsiveContainer.vue +99 -0
  63. package/src/components/ui/Select.md +187 -187
  64. package/src/components/ui/Select.vue +420 -420
  65. package/src/components/ui/TimePicker.md +50 -50
  66. package/src/components/ui/TimePicker.vue +252 -252
  67. package/src/components/ui/Tooltip.md +52 -52
  68. package/src/components/ui/Tooltip.vue +113 -113
  69. package/src/components/ui/utils/FormComponent.js +107 -107
  70. package/src/components/ui/utils/Helpers.js +61 -61
  71. package/src/components/ui/utils/WithPopover.js +81 -81
  72. package/src/main.js +8 -8
  73. package/styleguide.config.js +37 -37
  74. package/vue.config.js +8 -8
  75. package/dist/js.png +0 -0
@@ -1,527 +1,527 @@
1
- <template>
2
- <div class="ui-date-picker">
3
- <div class="panel d-inline-flex flex-col scroll-hide">
4
- <div class="row row-collapse row-vgap-none flex-nowrap">
5
- <div class="col col-auto" v-if="$scopedSlots.left">
6
- <!--
7
- @slot Custom left content
8
- -->
9
- <slot name="left"></slot>
10
- </div>
11
- <div class="col col-auto">
12
- <!--
13
- @slot Custom header content
14
- @binding {Function} prevYear select previous year
15
- @binding {Function} prevMonth select previous month
16
- @binding {Function} nextYear select next year
17
- @binding {Function} nextMonth select next month
18
- @binding {Function} setMonth set month by index (0 = january)
19
- @binding {Function} setYear set year (4-digit)
20
- @binding {Function} setToday set today's date
21
- @binding {Number} month current month index (0 = january)
22
- @binding {String} monthName current month name
23
- @binding {Number} year current year (4-digit)
24
- -->
25
- <slot
26
- name="header"
27
- v-bind="{
28
- prevYear,
29
- prevMonth,
30
- nextYear,
31
- nextMonth,
32
- setMonth,
33
- setYear,
34
- setToday,
35
- month,
36
- monthName: monthNames[month],
37
- year,
38
- }"
39
- >
40
- <div
41
- class="ui-date-picker-header text-small mar-bot-3 bg-primary color-white pad-3"
42
- >
43
- <div class="flex-shrink nobr">
44
- <div class="icon cursor-pointer" @click="prevYear">
45
- <i class="mdi mdi-chevron-double-left"></i>
46
- </div>
47
- <div class="icon cursor-pointer" @click="prevMonth">
48
- <i class="mdi mdi-chevron-left"></i>
49
- </div>
50
- </div>
51
- <div class="flex-grow flex-h-center d-flex">
52
- <span>{{ monthNames[month] }}</span>
53
- <input class="color-inherit" type="number" v-model.number="year" />
54
- </div>
55
- <div class="flex-shrink nobr">
56
- <div class="icon cursor-pointer" @click="nextMonth">
57
- <i class="mdi mdi-chevron-right"></i>
58
- </div>
59
- <div class="icon cursor-pointer" @click="nextYear">
60
- <i class="mdi mdi-chevron-double-right"></i>
61
- </div>
62
- </div>
63
- </div>
64
- </slot>
65
- <div class="ui-date-picker-grid pad-3">
66
- <div
67
- class="ui-date-picker-day-cell text-small"
68
- v-for="dayIndex of dayNamesIndexes"
69
- :key="`day-${dayIndex}`"
70
- >
71
- <!--
72
- @slot Custom day content
73
- @binding {Number} dayIndex day index (0 = sunday)
74
- @binding {String} dayName day name
75
- @binding {Boolean} isWeekend whether a weekend day
76
- -->
77
- <slot
78
- name="cell-day"
79
- v-bind="{
80
- dayIndex,
81
- dayName: dayNames[dayIndex],
82
- isWeekend: isWeekendDay(dayIndex),
83
- }"
84
- >
85
- <div class="color-grey-dark">
86
- {{ dayNames[dayIndex] }}
87
- </div>
88
- </slot>
89
- </div>
90
- <div
91
- class="ui-date-picker-date-cell text-small"
92
- v-for="n in currentMonthDates"
93
- :key="`${n.getMonth()}-${n.getDate()}`"
94
- >
95
- <!--
96
- @slot Custom date content
97
- @binding {Date} date date
98
- @binding {Date} dateStart range start date
99
- @binding {Date} dateEnd range end date
100
- @binding {Number} month current view month
101
- @binding {Number} year current view year
102
- @binding {Boolean} isCurrentMonthDate is date in current month view
103
- @binding {Boolean} isDisabledDate is date disabled
104
- @binding {Boolean} isInRange is date in range
105
- @binding {Boolean} isRangeStart is date = range start
106
- @binding {Boolean} isRangeEnd is date = range end
107
- @binding {Boolean} isSelected is date selected
108
- @binding {Boolean} isToday is date today
109
- @binding {Boolean} isWeekend is date a weekend day
110
- @binding {Function} setDate set date
111
- -->
112
- <slot
113
- name="cell-date"
114
- v-bind="{
115
- date: n,
116
- dateStart,
117
- dateEnd,
118
- month,
119
- year,
120
- isCurrentMonthDate: isCurrentMonthDate(n),
121
- isDisabledDate: isDisabledDate(n),
122
- isInRange: isRangeDate(n),
123
- isRangeStart: isRangeStartDate(n),
124
- isRangeEnd: isRangeEndDate(n),
125
- isSelected: isSelectedDate(n),
126
- isToday: isTodayDate(n),
127
- isWeekend: isWeekendDate(n),
128
- setDate,
129
- }"
130
- >
131
- <div
132
- class="btn btn-icon btn-small"
133
- :class="{
134
- 'btn-primary': isSelectedDate(n) || isRangeDate(n),
135
- 'radius-right-none':
136
- isRangeStartDate(n) && !isRangeEndDate(n) && dateEnd,
137
- 'radius-left-none':
138
- !isRangeStartDate(n) && isRangeEndDate(n),
139
- 'radius-none':
140
- isRangeDate(n) &&
141
- !isRangeStartDate(n) &&
142
- !isRangeEndDate(n),
143
- 'disabled radius-none': isDisabledDate(n),
144
- }"
145
- @click="setDate(n)"
146
- >
147
- <template v-if="isSelectedDate(n) || isRangeDate(n)">
148
- <div>{{ n.getDate() }}</div>
149
- </template>
150
- <template v-else-if="isTodayDate(n)">
151
- <div class="color-primary">{{ n.getDate() }}</div>
152
- </template>
153
- <template v-else-if="!isCurrentMonthDate(n)">
154
- <div class="text-muted">{{ n.getDate() }}</div>
155
- </template>
156
- <template v-else>
157
- <div class="color-body">{{ n.getDate() }}</div>
158
- </template>
159
- </div>
160
- </slot>
161
- </div>
162
- </div>
163
- </div>
164
- <div class="col col-auto" v-if="$scopedSlots.right">
165
- <!--
166
- @slot Custom right content
167
- -->
168
- <slot name="right"></slot>
169
- </div>
170
- </div>
171
- </div>
172
- </div>
173
- </template>
174
- <style lang="less" scoped>
175
- .ui-date-picker {
176
- display: inline-flex;
177
- color: var(--color-body);
178
- &-header {
179
- display: flex;
180
- align-items: center;
181
- input {
182
- width: 3em;
183
- border: none;
184
- background: transparent;
185
- outline: none;
186
- text-align: center;
187
- margin: 0;
188
- padding: 0;
189
- outline: none;
190
- -moz-appearance: textfield;
191
- &::-webkit-outer-spin-button,
192
- &::-webkit-inner-spin-button {
193
- -webkit-appearance: none;
194
- margin: 0;
195
- }
196
- }
197
- }
198
- &-grid {
199
- display: grid;
200
- grid-template-columns: repeat(7, 1fr);
201
- grid-auto-rows: 1fr;
202
- row-gap: 1px;
203
- }
204
- &-day-cell,
205
- &-date-cell {
206
- position: relative;
207
- display: flex;
208
- align-items: center;
209
- justify-content: center;
210
- }
211
- .flex-nowrap {
212
- flex-wrap: nowrap;
213
- }
214
- .radius-left-none {
215
- border-top-left-radius: 0;
216
- border-bottom-left-radius: 0;
217
- }
218
- .radius-right-none {
219
- border-top-right-radius: 0;
220
- border-bottom-right-radius: 0;
221
- }
222
- }
223
- </style>
224
- <script>
225
- import { isDateValid } from './utils/Helpers';
226
-
227
- export default {
228
- props: {
229
- /**
230
- * @model
231
- */
232
- value: {
233
- type: [Date, Array],
234
- default: null,
235
- validation(val) {
236
- if (Array.isArray(val)) {
237
- return val.find(el => !this.isValid(el)) == null;
238
- } else {
239
- return this.isValid(val);
240
- }
241
- },
242
- },
243
- /**
244
- * Min date (inclusive)
245
- */
246
- min: {
247
- type: Date,
248
- default: null,
249
- },
250
- /**
251
- * Max date (inclusive)
252
- */
253
- max: {
254
- type: Date,
255
- default: null,
256
- },
257
- /**
258
- * Allowed date filter function(date:Date):Boolean
259
- */
260
- allowed: {
261
- type: Function,
262
- default: () => true,
263
- },
264
- /**
265
- * Range mode
266
- */
267
- range: {
268
- type: Boolean,
269
- default: false,
270
- },
271
- /**
272
- * Day names starting from 'Sunday'
273
- */
274
- dayNames: {
275
- type: Array,
276
- default() {
277
- return ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'];
278
- },
279
- },
280
- /**
281
- * Weekend day indexes (0 = Sunday; 6 = Saturday)
282
- */
283
- weekendDays: {
284
- type: Array,
285
- default() {
286
- return [0, 6];
287
- },
288
- },
289
- /**
290
- * Month names starting from 'January'
291
- */
292
- monthNames: {
293
- type: Array,
294
- default() {
295
- return [
296
- 'Январь',
297
- 'Февраль',
298
- 'Март',
299
- 'Апрель',
300
- 'Май',
301
- 'Июнь',
302
- 'Июль',
303
- 'Август',
304
- 'Сентябрь',
305
- 'Октябрь',
306
- 'Ноябрь',
307
- 'Декабрь',
308
- ];
309
- },
310
- },
311
- /**
312
- * Which day is the first day of the week (0 = Sunday; 6 = Saturday)
313
- */
314
- dayOfWeek: {
315
- type: Number,
316
- default: 1,
317
- validation(val) {
318
- return val >= 0 && val < 7;
319
- },
320
- },
321
- },
322
- data() {
323
- return {
324
- date: null,
325
- dateStart: null,
326
- dateEnd: null,
327
- month: null,
328
- year: null,
329
- syncMonthYear: true,
330
- };
331
- },
332
- computed: {
333
- dayNamesIndexes() {
334
- let a = [];
335
- for (let i = this.dayOfWeek; i < 7 + this.dayOfWeek; ++i) {
336
- a.push(i >= 7 ? i - 7 : i);
337
- }
338
- return a;
339
- },
340
- firstDayOfMonth() {
341
- let n = new Date(this.year, this.month, 1).getDay() - this.dayOfWeek;
342
- return n < 0 ? 7 + n : n;
343
- },
344
- lastDayOfMonth() {
345
- let n = new Date(this.year, this.month + 1, 0).getDay() - this.dayOfWeek;
346
- return n < 0 ? 7 + n : n;
347
- },
348
- daysInMonth() {
349
- return new Date(this.year, this.month + 1, 0).getDate();
350
- },
351
- currentMonthDates() {
352
- let dates = [...new Array(this.daysInMonth)].map(
353
- (v, i) => new Date(this.year, this.month, i + 1)
354
- );
355
- return [...this.prevMonthDates, ...dates, ...this.nextMonthDates];
356
- },
357
- prevMonthDates() {
358
- let n = this.firstDayOfMonth;
359
- let pmd = new Date(this.year, this.month, 0).getDate();
360
- return [...new Array(n)]
361
- .map((v, i) => new Date(this.year, this.month - 1, pmd - i))
362
- .reverse();
363
- },
364
- nextMonthDates() {
365
- let n = 6 - this.lastDayOfMonth;
366
- return [...new Array(n)].map((v, i) => new Date(this.year, this.month + 1, i + 1));
367
- },
368
- },
369
- watch: {
370
- value: {
371
- handler(val) {
372
- let d = new Date();
373
- if (this.range && Array.isArray(val)) {
374
- let [start, end] = val;
375
- this.dateStart = start || null;
376
- this.dateEnd = end || null;
377
- d = start || d;
378
- } else {
379
- this.date = val;
380
- d = val || d;
381
- }
382
- if (this.syncMonthYear) {
383
- this.month = d.getMonth();
384
- this.year = d.getFullYear();
385
- }
386
- this.syncMonthYear = true;
387
- },
388
- immediate: true,
389
- },
390
- range() {
391
- this.date = null;
392
- this.dateStart = null;
393
- this.dateEnd = null;
394
- this._triggerChange();
395
- },
396
- },
397
- methods: {
398
- isValid(date) {
399
- return isDateValid(date);
400
- },
401
- prevMonth() {
402
- let n = this.month - 1;
403
- this.month = n < 0 ? 11 : n;
404
- this.year -= n < 0 ? 1 : 0;
405
- },
406
- prevYear() {
407
- this.year = this.year - 1;
408
- },
409
- nextMonth() {
410
- let n = this.month + 1;
411
- this.month = n > 11 ? 0 : n;
412
- this.year += n > 11 ? 1 : 0;
413
- },
414
- nextYear() {
415
- this.year = this.year + 1;
416
- },
417
- setYear(n) {
418
- this.year = n;
419
- },
420
- setMonth(n) {
421
- this.month = n;
422
- },
423
- setDate(date) {
424
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
425
-
426
- if (this.range) {
427
- if (!this.dateStart || (this.dateStart && this.dateEnd)) {
428
- this.dateStart = d;
429
- this.dateEnd = null;
430
- } else {
431
- if (d < this.dateStart) {
432
- this.dateEnd = this.dateStart;
433
- this.dateStart = d;
434
- } else if (d > this.dateStart) {
435
- this.dateEnd = d;
436
- } else {
437
- return;
438
- }
439
- this._triggerChange();
440
- }
441
- } else {
442
- this.date = d;
443
- this._triggerChange();
444
- }
445
- /**
446
- * Set date event
447
- * @property {Date} date
448
- */
449
- this.$emit('set-date', d);
450
- },
451
- setToday() {
452
- this.date = new Date();
453
- this.month = this.date.getMonth();
454
- this.year = this.date.getFullYear();
455
- this._triggerChange();
456
- /**
457
- * Set date event
458
- * @property {Date} date
459
- */
460
- this.$emit('set-date', this.date);
461
- },
462
- isCurrentMonthDate(date) {
463
- if (this.isValid(date)) {
464
- return this.month == date.getMonth();
465
- }
466
- return true;
467
- },
468
- isDisabledDate(date) {
469
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
470
- let { min, max, allowed } = this;
471
- return (min && d < min) || (max && d > max) || (allowed && !allowed(d));
472
- },
473
- isRangeStartDate(date) {
474
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
475
- return this.dateStart && +d == +this.dateStart;
476
- },
477
- isRangeEndDate(date) {
478
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
479
- return this.dateEnd && +d == +this.dateEnd;
480
- },
481
- isRangeDate(date) {
482
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
483
- if (this.dateStart && +d == +this.dateStart) {
484
- return true;
485
- }
486
- return this.dateStart && this.dateEnd && d >= this.dateStart && d <= this.dateEnd;
487
- },
488
- isSelectedDate(date) {
489
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
490
- return this.date && +this.date == +date;
491
- },
492
- isWeekendDate(date) {
493
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
494
- return this.weekendDays.includes(d.getDay());
495
- },
496
- isTodayDate(date) {
497
- let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
498
- let now = new Date();
499
- return (
500
- now.getFullYear() === d.getFullYear() &&
501
- now.getMonth() === d.getMonth() &&
502
- now.getDate() === d.getDate()
503
- );
504
- },
505
- isWeekendDay(day) {
506
- return this.weekendDays.includes(day);
507
- },
508
- _triggerChange() {
509
- let val = this.date;
510
- if (this.range) {
511
- val = this.dateStart && this.dateEnd ? [this.dateStart, this.dateEnd] : [];
512
- }
513
- this.syncMonthYear = false;
514
- /**
515
- * Date change event
516
- * @property {Date} date
517
- */
518
- this.$emit('input', val);
519
- /**
520
- * Date change event
521
- * @property {Date} date
522
- */
523
- this.$emit('change', val);
524
- },
525
- },
526
- };
527
- </script>
1
+ <template>
2
+ <div class="ui-date-picker">
3
+ <div class="panel d-inline-flex flex-col scroll-hide">
4
+ <div class="row row-collapse row-vgap-none flex-nowrap">
5
+ <div class="col col-auto" v-if="$scopedSlots.left">
6
+ <!--
7
+ @slot Custom left content
8
+ -->
9
+ <slot name="left"></slot>
10
+ </div>
11
+ <div class="col col-auto">
12
+ <!--
13
+ @slot Custom header content
14
+ @binding {Function} prevYear select previous year
15
+ @binding {Function} prevMonth select previous month
16
+ @binding {Function} nextYear select next year
17
+ @binding {Function} nextMonth select next month
18
+ @binding {Function} setMonth set month by index (0 = january)
19
+ @binding {Function} setYear set year (4-digit)
20
+ @binding {Function} setToday set today's date
21
+ @binding {Number} month current month index (0 = january)
22
+ @binding {String} monthName current month name
23
+ @binding {Number} year current year (4-digit)
24
+ -->
25
+ <slot
26
+ name="header"
27
+ v-bind="{
28
+ prevYear,
29
+ prevMonth,
30
+ nextYear,
31
+ nextMonth,
32
+ setMonth,
33
+ setYear,
34
+ setToday,
35
+ month,
36
+ monthName: monthNames[month],
37
+ year,
38
+ }"
39
+ >
40
+ <div
41
+ class="ui-date-picker-header text-small mar-bot-3 bg-primary color-white pad-3"
42
+ >
43
+ <div class="flex-shrink nobr">
44
+ <div class="icon cursor-pointer" @click="prevYear">
45
+ <i class="mdi mdi-chevron-double-left"></i>
46
+ </div>
47
+ <div class="icon cursor-pointer" @click="prevMonth">
48
+ <i class="mdi mdi-chevron-left"></i>
49
+ </div>
50
+ </div>
51
+ <div class="flex-grow flex-h-center d-flex">
52
+ <span>{{ monthNames[month] }}</span>
53
+ <input class="color-inherit" type="number" v-model.number="year" />
54
+ </div>
55
+ <div class="flex-shrink nobr">
56
+ <div class="icon cursor-pointer" @click="nextMonth">
57
+ <i class="mdi mdi-chevron-right"></i>
58
+ </div>
59
+ <div class="icon cursor-pointer" @click="nextYear">
60
+ <i class="mdi mdi-chevron-double-right"></i>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </slot>
65
+ <div class="ui-date-picker-grid pad-3">
66
+ <div
67
+ class="ui-date-picker-day-cell text-small"
68
+ v-for="dayIndex of dayNamesIndexes"
69
+ :key="`day-${dayIndex}`"
70
+ >
71
+ <!--
72
+ @slot Custom day content
73
+ @binding {Number} dayIndex day index (0 = sunday)
74
+ @binding {String} dayName day name
75
+ @binding {Boolean} isWeekend whether a weekend day
76
+ -->
77
+ <slot
78
+ name="cell-day"
79
+ v-bind="{
80
+ dayIndex,
81
+ dayName: dayNames[dayIndex],
82
+ isWeekend: isWeekendDay(dayIndex),
83
+ }"
84
+ >
85
+ <div class="color-grey-dark">
86
+ {{ dayNames[dayIndex] }}
87
+ </div>
88
+ </slot>
89
+ </div>
90
+ <div
91
+ class="ui-date-picker-date-cell text-small"
92
+ v-for="n in currentMonthDates"
93
+ :key="`${n.getMonth()}-${n.getDate()}`"
94
+ >
95
+ <!--
96
+ @slot Custom date content
97
+ @binding {Date} date date
98
+ @binding {Date} dateStart range start date
99
+ @binding {Date} dateEnd range end date
100
+ @binding {Number} month current view month
101
+ @binding {Number} year current view year
102
+ @binding {Boolean} isCurrentMonthDate is date in current month view
103
+ @binding {Boolean} isDisabledDate is date disabled
104
+ @binding {Boolean} isInRange is date in range
105
+ @binding {Boolean} isRangeStart is date = range start
106
+ @binding {Boolean} isRangeEnd is date = range end
107
+ @binding {Boolean} isSelected is date selected
108
+ @binding {Boolean} isToday is date today
109
+ @binding {Boolean} isWeekend is date a weekend day
110
+ @binding {Function} setDate set date
111
+ -->
112
+ <slot
113
+ name="cell-date"
114
+ v-bind="{
115
+ date: n,
116
+ dateStart,
117
+ dateEnd,
118
+ month,
119
+ year,
120
+ isCurrentMonthDate: isCurrentMonthDate(n),
121
+ isDisabledDate: isDisabledDate(n),
122
+ isInRange: isRangeDate(n),
123
+ isRangeStart: isRangeStartDate(n),
124
+ isRangeEnd: isRangeEndDate(n),
125
+ isSelected: isSelectedDate(n),
126
+ isToday: isTodayDate(n),
127
+ isWeekend: isWeekendDate(n),
128
+ setDate,
129
+ }"
130
+ >
131
+ <div
132
+ class="btn btn-icon btn-small"
133
+ :class="{
134
+ 'btn-primary': isSelectedDate(n) || isRangeDate(n),
135
+ 'radius-right-none':
136
+ isRangeStartDate(n) && !isRangeEndDate(n) && dateEnd,
137
+ 'radius-left-none':
138
+ !isRangeStartDate(n) && isRangeEndDate(n),
139
+ 'radius-none':
140
+ isRangeDate(n) &&
141
+ !isRangeStartDate(n) &&
142
+ !isRangeEndDate(n),
143
+ 'disabled radius-none': isDisabledDate(n),
144
+ }"
145
+ @click="setDate(n)"
146
+ >
147
+ <template v-if="isSelectedDate(n) || isRangeDate(n)">
148
+ <div>{{ n.getDate() }}</div>
149
+ </template>
150
+ <template v-else-if="isTodayDate(n)">
151
+ <div class="color-primary">{{ n.getDate() }}</div>
152
+ </template>
153
+ <template v-else-if="!isCurrentMonthDate(n)">
154
+ <div class="text-muted">{{ n.getDate() }}</div>
155
+ </template>
156
+ <template v-else>
157
+ <div class="color-body">{{ n.getDate() }}</div>
158
+ </template>
159
+ </div>
160
+ </slot>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ <div class="col col-auto" v-if="$scopedSlots.right">
165
+ <!--
166
+ @slot Custom right content
167
+ -->
168
+ <slot name="right"></slot>
169
+ </div>
170
+ </div>
171
+ </div>
172
+ </div>
173
+ </template>
174
+ <style lang="less" scoped>
175
+ .ui-date-picker {
176
+ display: inline-flex;
177
+ color: var(--color-body);
178
+ &-header {
179
+ display: flex;
180
+ align-items: center;
181
+ input {
182
+ width: 3em;
183
+ border: none;
184
+ background: transparent;
185
+ outline: none;
186
+ text-align: center;
187
+ margin: 0;
188
+ padding: 0;
189
+ outline: none;
190
+ -moz-appearance: textfield;
191
+ &::-webkit-outer-spin-button,
192
+ &::-webkit-inner-spin-button {
193
+ -webkit-appearance: none;
194
+ margin: 0;
195
+ }
196
+ }
197
+ }
198
+ &-grid {
199
+ display: grid;
200
+ grid-template-columns: repeat(7, 1fr);
201
+ grid-auto-rows: 1fr;
202
+ row-gap: 1px;
203
+ }
204
+ &-day-cell,
205
+ &-date-cell {
206
+ position: relative;
207
+ display: flex;
208
+ align-items: center;
209
+ justify-content: center;
210
+ }
211
+ .flex-nowrap {
212
+ flex-wrap: nowrap;
213
+ }
214
+ .radius-left-none {
215
+ border-top-left-radius: 0;
216
+ border-bottom-left-radius: 0;
217
+ }
218
+ .radius-right-none {
219
+ border-top-right-radius: 0;
220
+ border-bottom-right-radius: 0;
221
+ }
222
+ }
223
+ </style>
224
+ <script>
225
+ import { isDateValid } from './utils/Helpers';
226
+
227
+ export default {
228
+ props: {
229
+ /**
230
+ * @model
231
+ */
232
+ value: {
233
+ type: [Date, Array],
234
+ default: null,
235
+ validation(val) {
236
+ if (Array.isArray(val)) {
237
+ return val.find(el => !this.isValid(el)) == null;
238
+ } else {
239
+ return this.isValid(val);
240
+ }
241
+ },
242
+ },
243
+ /**
244
+ * Min date (inclusive)
245
+ */
246
+ min: {
247
+ type: Date,
248
+ default: null,
249
+ },
250
+ /**
251
+ * Max date (inclusive)
252
+ */
253
+ max: {
254
+ type: Date,
255
+ default: null,
256
+ },
257
+ /**
258
+ * Allowed date filter function(date:Date):Boolean
259
+ */
260
+ allowed: {
261
+ type: Function,
262
+ default: () => true,
263
+ },
264
+ /**
265
+ * Range mode
266
+ */
267
+ range: {
268
+ type: Boolean,
269
+ default: false,
270
+ },
271
+ /**
272
+ * Day names starting from 'Sunday'
273
+ */
274
+ dayNames: {
275
+ type: Array,
276
+ default() {
277
+ return ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'];
278
+ },
279
+ },
280
+ /**
281
+ * Weekend day indexes (0 = Sunday; 6 = Saturday)
282
+ */
283
+ weekendDays: {
284
+ type: Array,
285
+ default() {
286
+ return [0, 6];
287
+ },
288
+ },
289
+ /**
290
+ * Month names starting from 'January'
291
+ */
292
+ monthNames: {
293
+ type: Array,
294
+ default() {
295
+ return [
296
+ 'Январь',
297
+ 'Февраль',
298
+ 'Март',
299
+ 'Апрель',
300
+ 'Май',
301
+ 'Июнь',
302
+ 'Июль',
303
+ 'Август',
304
+ 'Сентябрь',
305
+ 'Октябрь',
306
+ 'Ноябрь',
307
+ 'Декабрь',
308
+ ];
309
+ },
310
+ },
311
+ /**
312
+ * Which day is the first day of the week (0 = Sunday; 6 = Saturday)
313
+ */
314
+ dayOfWeek: {
315
+ type: Number,
316
+ default: 1,
317
+ validation(val) {
318
+ return val >= 0 && val < 7;
319
+ },
320
+ },
321
+ },
322
+ data() {
323
+ return {
324
+ date: null,
325
+ dateStart: null,
326
+ dateEnd: null,
327
+ month: null,
328
+ year: null,
329
+ syncMonthYear: true,
330
+ };
331
+ },
332
+ computed: {
333
+ dayNamesIndexes() {
334
+ let a = [];
335
+ for (let i = this.dayOfWeek; i < 7 + this.dayOfWeek; ++i) {
336
+ a.push(i >= 7 ? i - 7 : i);
337
+ }
338
+ return a;
339
+ },
340
+ firstDayOfMonth() {
341
+ let n = new Date(this.year, this.month, 1).getDay() - this.dayOfWeek;
342
+ return n < 0 ? 7 + n : n;
343
+ },
344
+ lastDayOfMonth() {
345
+ let n = new Date(this.year, this.month + 1, 0).getDay() - this.dayOfWeek;
346
+ return n < 0 ? 7 + n : n;
347
+ },
348
+ daysInMonth() {
349
+ return new Date(this.year, this.month + 1, 0).getDate();
350
+ },
351
+ currentMonthDates() {
352
+ let dates = [...new Array(this.daysInMonth)].map(
353
+ (v, i) => new Date(this.year, this.month, i + 1)
354
+ );
355
+ return [...this.prevMonthDates, ...dates, ...this.nextMonthDates];
356
+ },
357
+ prevMonthDates() {
358
+ let n = this.firstDayOfMonth;
359
+ let pmd = new Date(this.year, this.month, 0).getDate();
360
+ return [...new Array(n)]
361
+ .map((v, i) => new Date(this.year, this.month - 1, pmd - i))
362
+ .reverse();
363
+ },
364
+ nextMonthDates() {
365
+ let n = 6 - this.lastDayOfMonth;
366
+ return [...new Array(n)].map((v, i) => new Date(this.year, this.month + 1, i + 1));
367
+ },
368
+ },
369
+ watch: {
370
+ value: {
371
+ handler(val) {
372
+ let d = new Date();
373
+ if (this.range && Array.isArray(val)) {
374
+ let [start, end] = val;
375
+ this.dateStart = start || null;
376
+ this.dateEnd = end || null;
377
+ d = start || d;
378
+ } else {
379
+ this.date = val;
380
+ d = val || d;
381
+ }
382
+ if (this.syncMonthYear) {
383
+ this.month = d.getMonth();
384
+ this.year = d.getFullYear();
385
+ }
386
+ this.syncMonthYear = true;
387
+ },
388
+ immediate: true,
389
+ },
390
+ range() {
391
+ this.date = null;
392
+ this.dateStart = null;
393
+ this.dateEnd = null;
394
+ this._triggerChange();
395
+ },
396
+ },
397
+ methods: {
398
+ isValid(date) {
399
+ return isDateValid(date);
400
+ },
401
+ prevMonth() {
402
+ let n = this.month - 1;
403
+ this.month = n < 0 ? 11 : n;
404
+ this.year -= n < 0 ? 1 : 0;
405
+ },
406
+ prevYear() {
407
+ this.year = this.year - 1;
408
+ },
409
+ nextMonth() {
410
+ let n = this.month + 1;
411
+ this.month = n > 11 ? 0 : n;
412
+ this.year += n > 11 ? 1 : 0;
413
+ },
414
+ nextYear() {
415
+ this.year = this.year + 1;
416
+ },
417
+ setYear(n) {
418
+ this.year = n;
419
+ },
420
+ setMonth(n) {
421
+ this.month = n;
422
+ },
423
+ setDate(date) {
424
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
425
+
426
+ if (this.range) {
427
+ if (!this.dateStart || (this.dateStart && this.dateEnd)) {
428
+ this.dateStart = d;
429
+ this.dateEnd = null;
430
+ } else {
431
+ if (d < this.dateStart) {
432
+ this.dateEnd = this.dateStart;
433
+ this.dateStart = d;
434
+ } else if (d > this.dateStart) {
435
+ this.dateEnd = d;
436
+ } else {
437
+ return;
438
+ }
439
+ this._triggerChange();
440
+ }
441
+ } else {
442
+ this.date = d;
443
+ this._triggerChange();
444
+ }
445
+ /**
446
+ * Set date event
447
+ * @property {Date} date
448
+ */
449
+ this.$emit('set-date', d);
450
+ },
451
+ setToday() {
452
+ this.date = new Date();
453
+ this.month = this.date.getMonth();
454
+ this.year = this.date.getFullYear();
455
+ this._triggerChange();
456
+ /**
457
+ * Set date event
458
+ * @property {Date} date
459
+ */
460
+ this.$emit('set-date', this.date);
461
+ },
462
+ isCurrentMonthDate(date) {
463
+ if (this.isValid(date)) {
464
+ return this.month == date.getMonth();
465
+ }
466
+ return true;
467
+ },
468
+ isDisabledDate(date) {
469
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
470
+ let { min, max, allowed } = this;
471
+ return (min && d < min) || (max && d > max) || (allowed && !allowed(d));
472
+ },
473
+ isRangeStartDate(date) {
474
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
475
+ return this.dateStart && +d == +this.dateStart;
476
+ },
477
+ isRangeEndDate(date) {
478
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
479
+ return this.dateEnd && +d == +this.dateEnd;
480
+ },
481
+ isRangeDate(date) {
482
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
483
+ if (this.dateStart && +d == +this.dateStart) {
484
+ return true;
485
+ }
486
+ return this.dateStart && this.dateEnd && d >= this.dateStart && d <= this.dateEnd;
487
+ },
488
+ isSelectedDate(date) {
489
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
490
+ return this.date && +this.date == +date;
491
+ },
492
+ isWeekendDate(date) {
493
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
494
+ return this.weekendDays.includes(d.getDay());
495
+ },
496
+ isTodayDate(date) {
497
+ let d = this.isValid(date) ? date : new Date(this.year, this.month, date);
498
+ let now = new Date();
499
+ return (
500
+ now.getFullYear() === d.getFullYear() &&
501
+ now.getMonth() === d.getMonth() &&
502
+ now.getDate() === d.getDate()
503
+ );
504
+ },
505
+ isWeekendDay(day) {
506
+ return this.weekendDays.includes(day);
507
+ },
508
+ _triggerChange() {
509
+ let val = this.date;
510
+ if (this.range) {
511
+ val = this.dateStart && this.dateEnd ? [this.dateStart, this.dateEnd] : [];
512
+ }
513
+ this.syncMonthYear = false;
514
+ /**
515
+ * Date change event
516
+ * @property {Date} date
517
+ */
518
+ this.$emit('input', val);
519
+ /**
520
+ * Date change event
521
+ * @property {Date} date
522
+ */
523
+ this.$emit('change', val);
524
+ },
525
+ },
526
+ };
527
+ </script>