@king-design/intact 3.6.0-beta.0 → 3.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/components/button/demos/basic.md +0 -1
  2. package/components/cascader/index.spec.ts +7 -6
  3. package/components/copy/index.spec.ts +9 -14
  4. package/components/datepicker/basepicker.ts +26 -314
  5. package/components/datepicker/calendar.ts +3 -1
  6. package/components/datepicker/calendar.vdt +5 -2
  7. package/components/datepicker/dayjs.ts +2 -16
  8. package/components/datepicker/demos/multiple.md +5 -0
  9. package/components/datepicker/demos/yearMonth.md +2 -8
  10. package/components/datepicker/helpers.ts +5 -7
  11. package/components/datepicker/index.md +1 -2
  12. package/components/datepicker/index.spec.ts +596 -157
  13. package/components/datepicker/index.ts +16 -33
  14. package/components/datepicker/index.vdt +41 -35
  15. package/components/datepicker/shortcuts.ts +1 -1
  16. package/components/datepicker/styles.ts +27 -18
  17. package/components/datepicker/useConfirm.ts +82 -0
  18. package/components/datepicker/useDisabled.ts +29 -31
  19. package/components/datepicker/useFormats.ts +8 -4
  20. package/components/datepicker/useHighlight.ts +81 -0
  21. package/components/datepicker/useKeyboards.ts +2 -1
  22. package/components/datepicker/useMergeRange.ts +12 -12
  23. package/components/datepicker/useMonths.ts +6 -3
  24. package/components/datepicker/usePanel.ts +19 -19
  25. package/components/datepicker/useShowDate.ts +21 -41
  26. package/components/datepicker/useStatus.ts +34 -15
  27. package/components/datepicker/useValue.ts +43 -72
  28. package/components/datepicker/useValueBase.ts +312 -0
  29. package/components/datepicker/useWeeks.ts +1 -1
  30. package/components/datepicker/useYears.ts +7 -3
  31. package/components/dropdown/dropdown.ts +5 -4
  32. package/components/dropdown/index.md +1 -0
  33. package/components/dropdown/item.ts +1 -1
  34. package/components/dropdown/useKeyboard.ts +0 -1
  35. package/components/form/form.ts +4 -0
  36. package/components/form/index.md +2 -1
  37. package/components/form/index.spec.ts +2 -0
  38. package/components/input/index.spec.ts +42 -0
  39. package/components/input/index.ts +8 -0
  40. package/components/input/index.vdt +3 -4
  41. package/components/input/useAutoWidth.ts +19 -1
  42. package/components/menu/demos/horizontal.md +7 -1
  43. package/components/menu/index.spec.ts +19 -0
  44. package/components/menu/styles.ts +2 -1
  45. package/components/scrollSelect/useMouseEvents.ts +5 -4
  46. package/components/select/base.ts +3 -2
  47. package/components/select/base.vdt +2 -1
  48. package/components/select/demos/creatable.md +2 -2
  49. package/components/select/index.md +1 -1
  50. package/components/select/index.spec.ts +142 -36
  51. package/components/select/menu.ts +1 -1
  52. package/components/select/option.ts +2 -1
  53. package/components/select/select.ts +1 -0
  54. package/components/select/styles.ts +3 -1
  55. package/components/select/useCard.ts +22 -4
  56. package/components/select/useInput.ts +5 -9
  57. package/components/spinner/index.spec.ts +18 -0
  58. package/components/spinner/useValue.ts +2 -1
  59. package/components/table/index.spec.ts +69 -1
  60. package/components/table/useStickyHeader.ts +1 -1
  61. package/components/timepicker/index.spec.ts +145 -27
  62. package/components/timepicker/panelPicker.ts +10 -4
  63. package/components/timepicker/panelPicker.vdt +3 -5
  64. package/components/timepicker/styles.ts +1 -0
  65. package/components/timepicker/useConfirm.ts +33 -0
  66. package/components/timepicker/useDefaultValue.ts +30 -0
  67. package/components/timepicker/useDisabled.ts +17 -4
  68. package/components/timepicker/useFormats.ts +1 -1
  69. package/components/timepicker/useValue.ts +22 -19
  70. package/components/tour/index.spec.ts +1 -1
  71. package/es/components/cascader/index.spec.js +18 -19
  72. package/es/components/copy/index.spec.js +14 -31
  73. package/es/components/datepicker/basepicker.d.ts +6 -27
  74. package/es/components/datepicker/basepicker.js +23 -268
  75. package/es/components/datepicker/calendar.d.ts +4 -2
  76. package/es/components/datepicker/dayjs.d.ts +2 -13
  77. package/es/components/datepicker/helpers.d.ts +3 -2
  78. package/es/components/datepicker/helpers.js +2 -3
  79. package/es/components/datepicker/index.d.ts +21 -29
  80. package/es/components/datepicker/index.js +22 -32
  81. package/es/components/datepicker/index.spec.js +1277 -484
  82. package/es/components/datepicker/index.vdt.js +39 -38
  83. package/es/components/datepicker/shortcuts.d.ts +1 -1
  84. package/es/components/datepicker/styles.d.ts +7 -2
  85. package/es/components/datepicker/styles.js +10 -15
  86. package/es/components/datepicker/useConfirm.d.ts +6 -0
  87. package/es/components/datepicker/useConfirm.js +65 -0
  88. package/es/components/datepicker/useDisabled.d.ts +5 -3
  89. package/es/components/datepicker/useDisabled.js +22 -27
  90. package/es/components/datepicker/useFormats.d.ts +2 -2
  91. package/es/components/datepicker/useFormats.js +6 -2
  92. package/es/components/datepicker/useHighlight.d.ts +14 -0
  93. package/es/components/datepicker/useHighlight.js +60 -0
  94. package/es/components/datepicker/useKeyboards.js +2 -1
  95. package/es/components/datepicker/useMergeRange.d.ts +1 -1
  96. package/es/components/datepicker/useMergeRange.js +11 -16
  97. package/es/components/datepicker/useMonths.js +5 -3
  98. package/es/components/datepicker/usePanel.d.ts +1 -10
  99. package/es/components/datepicker/usePanel.js +19 -32
  100. package/es/components/datepicker/useShowDate.d.ts +1 -1
  101. package/es/components/datepicker/useShowDate.js +15 -40
  102. package/es/components/datepicker/useStatus.js +33 -16
  103. package/es/components/datepicker/useValue.d.ts +11 -6
  104. package/es/components/datepicker/useValue.js +49 -69
  105. package/es/components/datepicker/useValueBase.d.ts +28 -0
  106. package/es/components/datepicker/useValueBase.js +280 -0
  107. package/es/components/datepicker/useYears.js +6 -3
  108. package/es/components/dropdown/dropdown.d.ts +1 -0
  109. package/es/components/dropdown/dropdown.js +7 -4
  110. package/es/components/form/form.d.ts +1 -0
  111. package/es/components/form/form.js +7 -0
  112. package/es/components/form/index.spec.js +10 -8
  113. package/es/components/input/index.d.ts +2 -0
  114. package/es/components/input/index.js +6 -0
  115. package/es/components/input/index.spec.js +45 -0
  116. package/es/components/input/index.vdt.js +4 -3
  117. package/es/components/input/useAutoWidth.d.ts +2 -0
  118. package/es/components/input/useAutoWidth.js +19 -1
  119. package/es/components/menu/index.spec.js +28 -0
  120. package/es/components/menu/styles.js +2 -2
  121. package/es/components/scrollSelect/useMouseEvents.js +5 -4
  122. package/es/components/select/base.d.ts +1 -1
  123. package/es/components/select/base.js +3 -2
  124. package/es/components/select/base.vdt.js +4 -3
  125. package/es/components/select/index.spec.js +346 -218
  126. package/es/components/select/menu.js +1 -1
  127. package/es/components/select/option.js +2 -1
  128. package/es/components/select/select.js +2 -1
  129. package/es/components/select/styles.d.ts +79 -0
  130. package/es/components/select/styles.js +1 -0
  131. package/es/components/select/useCard.d.ts +4 -3
  132. package/es/components/select/useCard.js +15 -4
  133. package/es/components/select/useInput.d.ts +1 -1
  134. package/es/components/select/useInput.js +4 -4
  135. package/es/components/spinner/index.spec.js +82 -44
  136. package/es/components/spinner/useValue.js +2 -1
  137. package/es/components/table/index.spec.js +84 -6
  138. package/es/components/table/useStickyHeader.js +1 -1
  139. package/es/components/timepicker/index.spec.js +298 -128
  140. package/es/components/timepicker/panelPicker.d.ts +21 -16
  141. package/es/components/timepicker/panelPicker.js +7 -4
  142. package/es/components/timepicker/panelPicker.vdt.js +5 -9
  143. package/es/components/timepicker/selectPicker.d.ts +4 -3
  144. package/es/components/timepicker/styles.js +1 -1
  145. package/es/components/timepicker/useConfirm.d.ts +6 -0
  146. package/es/components/timepicker/useConfirm.js +19 -0
  147. package/es/components/timepicker/useDefaultValue.d.ts +4 -0
  148. package/es/components/timepicker/useDefaultValue.js +27 -0
  149. package/es/components/timepicker/useDisabled.d.ts +6 -3
  150. package/es/components/timepicker/useDisabled.js +13 -4
  151. package/es/components/timepicker/useFormats.d.ts +1 -1
  152. package/es/components/timepicker/useValue.d.ts +13 -8
  153. package/es/components/timepicker/useValue.js +14 -15
  154. package/es/components/tour/index.spec.js +1 -1
  155. package/es/index.d.ts +2 -2
  156. package/es/index.js +2 -2
  157. package/es/site/data/components/button/demos/basic/react.js +0 -2
  158. package/es/site/data/components/datepicker/demos/multiple/index.d.ts +1 -0
  159. package/es/site/data/components/datepicker/demos/multiple/index.js +2 -1
  160. package/es/site/data/components/datepicker/demos/multiple/react.d.ts +1 -0
  161. package/es/site/data/components/datepicker/demos/multiple/react.js +13 -2
  162. package/es/site/data/components/datepicker/demos/yearMonth/index.d.ts +0 -2
  163. package/es/site/data/components/datepicker/demos/yearMonth/index.js +1 -3
  164. package/es/site/data/components/datepicker/demos/yearMonth/react.d.ts +0 -2
  165. package/es/site/data/components/datepicker/demos/yearMonth/react.js +1 -21
  166. package/es/site/data/components/menu/demos/horizontal/react.js +5 -1
  167. package/es/site/data/components/select/demos/creatable/react.js +2 -2
  168. package/es/site/data/components/select/demos/searchable/index.js +1 -1
  169. package/es/site/data/components/select/demos/searchable/react.js +1 -1
  170. package/es/site/data/components/tour/demos/customText/index.d.ts +19 -6
  171. package/es/site/data/components/tour/demos/customText/index.js +18 -17
  172. package/es/site/data/components/tour/demos/customText/react.d.ts +20 -6
  173. package/es/site/data/components/tour/demos/customText/react.js +31 -27
  174. package/es/test/demos.js +1 -1
  175. package/index.ts +2 -2
  176. package/package.json +2 -2
  177. package/components/datepicker/demos/nowrap.md +0 -35
  178. package/components/datepicker/usePosition.ts +0 -169
  179. package/es/components/datepicker/usePosition.d.ts +0 -10
  180. package/es/components/datepicker/usePosition.js +0 -166
  181. package/es/site/data/components/datepicker/demos/nowrap/index.d.ts +0 -10
  182. package/es/site/data/components/datepicker/demos/nowrap/index.js +0 -19
  183. package/es/site/data/components/datepicker/demos/nowrap/react.d.ts +0 -10
  184. package/es/site/data/components/datepicker/demos/nowrap/react.js +0 -49
  185. package/es/site/data/components/tour/demos/customButtons/index.d.ts +0 -33
  186. package/es/site/data/components/tour/demos/customButtons/index.js +0 -55
  187. package/es/site/data/components/tour/demos/customButtons/react.d.ts +0 -33
  188. package/es/site/data/components/tour/demos/customButtons/react.js +0 -99
@@ -16,6 +16,26 @@ const now = new Date();
16
16
  const year = now.getFullYear();
17
17
  const startYear = Math.floor(year / 10) * 10;
18
18
  const month = now.getMonth();
19
+ const dateString = dayjs(now).format('YYYY-MM-DD');
20
+
21
+ async function clickConfirm(content: HTMLElement) {
22
+ await wait();
23
+ const confirm = content.querySelector('.k-datepicker-footer .k-btn') as HTMLElement;
24
+ confirm.click();
25
+ await wait();
26
+
27
+ return confirm;
28
+ }
29
+
30
+ function checkDisplay(content: HTMLElement, isShow: boolean) {
31
+ const className = content.className;
32
+ const isLeave = className.includes('-leave-');
33
+ expect(isLeave).eql(!isShow);
34
+ }
35
+
36
+ function getDateString(date: number) {
37
+ return dayjs(now).date(date).format('YYYY-MM-DD');
38
+ }
19
39
 
20
40
  describe('Datepicker', () => {
21
41
  afterEach(async () => {
@@ -32,23 +52,74 @@ describe('Datepicker', () => {
32
52
  await wait();
33
53
  const content = getElement('.k-datepicker-content')!;
34
54
  (content.querySelector('.k-calendar-item') as HTMLDivElement).click();
55
+ await wait();
35
56
  expect(instance.get('date')).to.be.string;
57
+ checkDisplay(content, false);
36
58
  });
37
59
 
38
- it('datetime', async () => {
39
- const [instance, element] = mount(DatetimeDemo);
60
+ describe('datetime', () => {
61
+ it('basic', async () => {
62
+ const [instance, element] = mount(DatetimeDemo);
40
63
 
41
- const input = element.querySelector('.k-input') as HTMLElement;
42
- input.click();
43
- await wait();
44
- const content = getElement('.k-datepicker-content')!;
45
- // change to time panel
46
- (content.querySelector('.k-calendar-item') as HTMLElement).click();
47
- await wait();
48
- dispatchEvent(content.querySelector('.k-scroll-select-item')!, 'click');
49
- (content.querySelector('.k-datepicker-footer .k-btn') as HTMLElement).click();
64
+ const input = element.querySelector('.k-input') as HTMLElement;
65
+ input.click();
66
+ await wait();
67
+ const content = getElement('.k-datepicker-content')!;
68
+ // change to time panel
69
+ (content.querySelector('.k-calendar-item') as HTMLElement).click();
70
+ await wait();
71
+ dispatchEvent(content.querySelector('.k-scroll-select-item')!, 'click');
72
+ (content.querySelector('.k-datepicker-footer .k-btn') as HTMLElement).click();
73
+
74
+ expect(instance.get<string>('datetime1').split(' ')[1]).eql('15:00:00');
75
+ });
76
+
77
+ it('skip select date and select time directly', async () => {
78
+ const [instance, element] = mount(DatetimeDemo);
79
+
80
+ const input = element.querySelector('.k-input') as HTMLElement;
81
+ let content: HTMLElement;
82
+ async function show() {
83
+ input.click();
84
+ await wait();
85
+ content = getElement('.k-datepicker-content')!;
86
+ }
87
+
88
+ await show();
89
+ dispatchEvent(content!.querySelector('.k-scroll-select-item')!, 'click');
90
+ await wait();
91
+ const inputInner = input.querySelector('.k-input-inner') as HTMLInputElement;
92
+ expect(inputInner.value).eql(`${dateString} 15:00:00`);
93
+ expect(instance.get('datetime1')).eql(null);
94
+
95
+ // hide to reset selected state
96
+ document.body.click();
97
+ await wait();
98
+ expect(inputInner.getAttribute('placeholder')).eql(`请选择日期和时间`);
99
+ expect(inputInner.value).eql('');
100
+ expect(instance.get('datetime1')).eql(null);
101
+
102
+ // show again
103
+ await show();
104
+ dispatchEvent(content!.querySelector('.k-scroll-select-item')!, 'click');
105
+ await wait();
106
+ const confirm = content!.querySelector('.k-datepicker-footer .k-btn') as HTMLElement;
107
+ confirm.click();
108
+ await wait();
109
+ expect(inputInner.value).eql(`${dateString} 15:00:00`);
110
+ expect(instance.get('datetime1')).eql(`${dateString} 15:00:00`);
50
111
 
51
- expect(instance.get<string>('datetime1').split(' ')[1]).eql('15:00:00');
112
+ checkDisplay(content!, false);
113
+
114
+ // change time
115
+ await show();
116
+ const activeHour = content!.querySelector('.k-scroll-select-item.k-active') as HTMLElement;
117
+ dispatchEvent(activeHour.nextElementSibling!, 'click');
118
+ await wait();
119
+ confirm.click();
120
+ await wait();
121
+ expect(instance.get('datetime1')).eql(`${dateString} 16:00:00`);
122
+ });
52
123
  });
53
124
 
54
125
  it('year', async () => {
@@ -80,38 +151,37 @@ describe('Datepicker', () => {
80
151
  expect(+_month - 1).eql(month);
81
152
  });
82
153
 
83
- it('week', async () => {
84
- const [instance, element] = mount(YearMonthDemo);
85
- const inputs = element.querySelectorAll<HTMLElement>('.k-input');
86
- const WeekInput = inputs[2];
154
+ // it('week', async () => {
155
+ // const [instance, element] = mount(YearMonthDemo);
156
+ // const inputs = element.querySelectorAll<HTMLElement>('.k-input');
157
+ // const weekInput = inputs[2];
87
158
 
88
- WeekInput.click();
89
- await wait();
159
+ // weekInput.click();
160
+ // await wait();
90
161
 
91
- const content = getElement('.k-datepicker-content')!;
92
- const weekItem = content.querySelector('.week-row:nth-child(1) .k-week-number') as HTMLElement;
93
- weekItem.click();
162
+ // const content = getElement('.k-datepicker-content')!;
163
+ // const weekItem = content.querySelector('.week-row:nth-child(1) .k-week-number') as HTMLElement;
164
+ // weekItem.click();
94
165
 
95
- expect(instance.get<string>('week')).to.match(/^\d{4}-\d+周$/)
96
-
97
- });
166
+ // expect(instance.get<string>('week')).to.match(/^\d{4}-\d+周$/)
167
+ // });
98
168
 
99
- it('quarter', async () => {
100
- const [instance, element] = mount(YearMonthDemo);
101
- const inputs = element.querySelectorAll<HTMLElement>('.k-input');
102
- const QuarterInput = inputs[3];
169
+ // it('quarter', async () => {
170
+ // const [instance, element] = mount(YearMonthDemo);
171
+ // const inputs = element.querySelectorAll<HTMLElement>('.k-input');
172
+ // const QuarterInput = inputs[3];
103
173
 
104
- QuarterInput.click();
105
- await wait();
106
- const content = getElement('.k-datepicker-content')!;
174
+ // QuarterInput.click();
175
+ // await wait();
176
+ // const content = getElement('.k-datepicker-content')!;
107
177
 
108
- // 选择第一个季度
109
- const quarterItem = content.querySelector('.k-calendar-item:nth-child(1)') as HTMLElement;
110
- quarterItem.click();
178
+ // // 选择第一个季度
179
+ // const quarterItem = content.querySelector('.k-calendar-item:nth-child(1)') as HTMLElement;
180
+ // quarterItem.click();
111
181
 
112
- // 验证输入框的值是否包含Q1
113
- expect(instance.get<string>('quarter')).to.include('Q1')
114
- });
182
+ // // 验证输入框的值是否包含Q1
183
+ // expect(instance.get<string>('quarter')).to.include('Q1')
184
+ // });
115
185
 
116
186
  });
117
187
 
@@ -359,14 +429,21 @@ describe('Datepicker', () => {
359
429
  await wait();
360
430
  expect(instance.get('datetime')).have.lengthOf(2);
361
431
 
362
- // change to time panel, and remove the selections, then click confirm ok
363
- dispatchEvent(content.querySelector('.k-calendar-item:nth-child(18)')!, 'click');
432
+ // select time directly
433
+ const activeHour = content.querySelector('.k-scroll-select-item.k-active') as HTMLElement;
434
+ dispatchEvent(activeHour.nextElementSibling!, 'click');
364
435
  await wait();
365
- instance.set('datetime', []);
436
+ const confirm = await clickConfirm(content);
437
+ expect(instance.get('datetime')).have.lengthOf(3);
438
+
439
+ // select time firstly, then select date should only add one value
440
+ dispatchEvent(activeHour.nextElementSibling!.nextElementSibling!, 'click');
366
441
  await wait();
367
- dispatchEvent(content.querySelector('.k-datepicker-footer .k-btn')!, 'click');
442
+ dispatchEvent(content.querySelector('.k-calendar-item:nth-child(19)')!, 'click');
368
443
  await wait();
369
- expect(instance.get('datetime')).have.lengthOf(1);
444
+ confirm.click();
445
+ await wait();
446
+ expect(instance.get('datetime')).have.lengthOf(4);
370
447
  });
371
448
 
372
449
  it('year', async () => {
@@ -411,141 +488,475 @@ describe('Datepicker', () => {
411
488
  expect(instance.get('month')).have.lengthOf(1);
412
489
  });
413
490
 
414
- it('date range', async () => {
415
- const [instance, element] = mount(MultipleDemo);
491
+ describe('date range', async () => {
492
+ it('date range', async () => {
493
+ const [instance, element] = mount(MultipleDemo);
416
494
 
417
- const [, , , , select] = element.querySelectorAll<HTMLElement>('.k-datepicker');
418
- dispatchEvent(select, 'click');
419
- await wait();
420
- const content = getElement('.k-datepicker-content')!;
421
- const [calendar1, calendar2] = content.querySelectorAll('.k-datepicker-calendar-time-wrapper');
495
+ const [, , , , select] = element.querySelectorAll<HTMLElement>('.k-datepicker');
496
+ dispatchEvent(select, 'click');
497
+ await wait();
498
+ const content = getElement('.k-datepicker-content')!;
499
+ const [calendar1, calendar2] = content.querySelectorAll('.k-datepicker-calendar-time-wrapper');
422
500
 
423
-
424
- const first = calendar1.querySelectorAll('.k-calendar-item')[17] as HTMLElement;
425
- const second = calendar2.querySelectorAll('.k-calendar-item')[17] as HTMLElement;
426
- first.click();
427
- second.click();
428
- await wait();
429
- expect(instance.get('dateRange')).have.lengthOf(1);
501
+ const first = calendar1.querySelector('.k-calendar-item:not(.k-exceed)') as HTMLElement;
502
+ const second = first.nextElementSibling as HTMLElement;
503
+ first.click();
504
+ second.click();
505
+ await wait();
506
+ const value1 = [`${getDateString(1)}`, `${getDateString(2)}`]
507
+ expect(instance.get('dateRange')).eql([value1]);
430
508
 
431
- dispatchEvent(first.nextElementSibling!, 'click');
432
- dispatchEvent(second.nextElementSibling!, 'click');
433
- await wait();
434
- expect(instance.get('dateRange')).have.lengthOf(2);
509
+ const third = second.nextElementSibling as HTMLElement;
510
+ const fourth = third.nextElementSibling as HTMLElement;
511
+ third.click();
512
+ fourth.click();
513
+ await wait();
514
+ const value2 = [`${getDateString(3)}`, `${getDateString(4)}`]
515
+ expect(instance.get('dateRange')).eql([value1, value2]);
435
516
 
436
- first.click();
437
- second.click();
438
- await wait();
439
- expect(instance.get('dateRange')).have.lengthOf(1);
517
+ first.click();
518
+ second.click();
519
+ await wait();
520
+ expect(instance.get('dateRange')).eql([value2]);
440
521
 
441
- instance.set('dateRange', []);
442
- await wait();
443
- first.click();
444
- second.click();
445
- await wait();
446
- expect(instance.get('dateRange')).have.lengthOf(1);
522
+ instance.set('dateRange', []);
523
+ await wait();
524
+ first.click();
525
+ second.click();
526
+ await wait();
527
+ expect(instance.get('dateRange')).eql([value1]);
528
+ });
529
+
530
+ it('hover status', async () => {
531
+ const [instance, element] = mount(MultipleDemo);
532
+
533
+ instance.set('dateRange', [['2025-07-11', '2025-07-15']]);
534
+ const [, , , , select] = element.querySelectorAll<HTMLElement>('.k-datepicker');
535
+ dispatchEvent(select, 'click');
536
+ await wait();
537
+ const content = getElement('.k-datepicker-content')!;
538
+ const [calendar1, calendar2] = content.querySelectorAll('.k-datepicker-calendar-time-wrapper');
539
+
540
+ const first = calendar1.querySelector('.k-calendar-item:not(.k-exceed)') as HTMLElement;
541
+ const second = first.nextElementSibling as HTMLElement;
542
+ dispatchEvent(first, 'mouseenter');
543
+ await wait();
544
+ expect(second.classList.contains('k-in-range')).eql(false);
545
+ });
447
546
  });
448
547
 
548
+ describe('datetime range', async () => {
549
+ it('basic', async () => {
550
+ const [instance, element] = mount(MultipleDemo);
551
+
552
+ const [, , , , , select] = element.querySelectorAll<HTMLElement>('.k-datepicker');
553
+ dispatchEvent(select, 'click');
554
+ await wait();
555
+ const content = getElement('.k-datepicker-content')!;
556
+ const calendar1 = content.querySelector('.k-datepicker-wrapper') as HTMLElement;
557
+ const first = calendar1.querySelector('.k-calendar-item:not(.k-exceed)') as HTMLElement;
558
+ const second = first.nextElementSibling as HTMLElement;
559
+ const inputInner = select.querySelector('.k-input-inner') as HTMLInputElement;
560
+ first.click();
561
+ await clickConfirm(content);
562
+ expect(inputInner.value).eql(`${getDateString(1)} 00:00:00 ~`);
563
+ second.click();
564
+ await wait();
565
+ expect(inputInner.value).eql(`${getDateString(1)} 00:00:00 ~ ${getDateString(2)} 00:00:00`);
566
+ await clickConfirm(content);
567
+ const value1 = [`${getDateString(1)} 00:00:00`, `${getDateString(2)} 00:00:00`];
568
+ expect(instance.get('datetimeRange')).eql([value1]);
569
+
570
+ const third = second.nextElementSibling as HTMLElement;
571
+ const fourth = third.nextElementSibling as HTMLElement;
572
+ third.click();
573
+ await clickConfirm(content);
574
+ fourth.click();
575
+ await clickConfirm(content);
576
+ const value2 = [`${getDateString(3)} 00:00:00`, `${getDateString(4)} 00:00:00`]
577
+ expect(instance.get('datetimeRange')).eql([value1, value2]);
578
+
579
+ // selecting the same date time will do nothing
580
+ third.click();
581
+ await clickConfirm(content);
582
+ fourth.click();
583
+ await clickConfirm(content);
584
+ expect(instance.get('datetimeRange')).eql([value1, value2]);
585
+
586
+ instance.set('datetimeRange', []);
587
+ await wait();
588
+ first.click();
589
+ await clickConfirm(content);
590
+ second.click();
591
+ const confirm = await clickConfirm(content);
592
+ expect(instance.get('datetimeRange')).eql([value1]);
593
+ expect(confirm.classList.contains('k-disabled')).eql(true);
594
+ });
595
+
596
+ it('select time directly', async () => {
597
+ const [instance, element] = mount(MultipleDemo);
598
+
599
+ const [, , , , , select] = element.querySelectorAll<HTMLElement>('.k-datepicker');
600
+ dispatchEvent(select, 'click');
601
+ await wait();
602
+ const content = getElement('.k-datepicker-content')!;
603
+ const calendar = content.querySelector('.k-datepicker-wrapper') as HTMLElement;
604
+
605
+ const activeHour = calendar.querySelector('.k-scroll-select-item.k-active') as HTMLElement;
606
+ (activeHour.nextElementSibling as HTMLElement).click();
607
+ await clickConfirm(content);
608
+ (activeHour.nextElementSibling as HTMLElement).click();
609
+ await clickConfirm(content);
610
+ expect(instance.get('datetimeRange')).to.eql([[`${dateString} 01:00:00`, `${dateString} 02:00:00`]]);
611
+ });
612
+ });
449
613
  });
450
614
 
451
615
  describe('Range', () => {
452
- it('date', async () => {
453
- const [instance, element] = mount(RangeDemo);
454
-
455
- // date
456
- const select = element.querySelector('.k-datepicker') as HTMLElement;
457
- select.click();
458
- await wait();
459
- let content = getElement('.k-datepicker-content')!;
460
- // select the middle date
461
- let first = content.querySelector('.k-calendar-item:nth-child(18)') as HTMLElement;
462
- first.click();
463
- await wait();
464
- expect(instance.get('date')).to.be.null;
465
- // hover status
466
- dispatchEvent(first.nextElementSibling!.nextElementSibling!, 'mouseenter');
467
- await wait();
468
- expect(first.nextElementSibling!.classList.contains('k-in-range')).to.be.true;
469
- dispatchEvent(first.previousElementSibling!.previousElementSibling!, 'mouseenter');
470
- await wait();
471
- expect(first.previousElementSibling!.classList.contains('k-in-range')).to.be.true;
472
- expect(first.nextElementSibling!.classList.contains('k-in-range')).to.be.false;
473
- dispatchEvent(first.previousElementSibling!.previousElementSibling!, 'click');
474
- await wait();
475
- const value = instance.get('date')!;
476
- expect(value).have.lengthOf(2);
477
- expect(value[0] < value[1]).to.be.true;
616
+ describe('date', async () => {
617
+ let instance: RangeDemo;
618
+ let element: HTMLElement;
619
+ let select: HTMLElement;
620
+ let content: HTMLElement;
621
+ let first: HTMLElement;
622
+
623
+ beforeEach(async () => {
624
+ const result = mount(RangeDemo);
625
+ instance = result[0];
626
+ element = result[1];
627
+
628
+ // date
629
+ select = element.querySelector('.k-datepicker') as HTMLElement;
630
+ select.click();
631
+ await wait();
632
+ content = getElement('.k-datepicker-content')!;
633
+ // select the middle date
634
+ first = content.querySelector('.k-calendar-item:nth-child(18)') as HTMLElement;
635
+ });
478
636
 
479
- // select the same date
480
- select.click();
481
- await wait();
482
- // select the middle date
483
- first.click();
484
- first.click();
485
- await wait();
486
- const value1 = instance.get('date')!;
487
- expect(value1).have.lengthOf(2);
488
- expect(value1[0]).eql(value1[1]);
637
+ it('basic selection', async () => {
638
+ first.click();
639
+ await wait();
640
+ expect(instance.get('date')).to.be.null;
641
+ // hover status
642
+ dispatchEvent(first.nextElementSibling!.nextElementSibling!, 'mouseenter');
643
+ await wait();
644
+ expect(first.nextElementSibling!.classList.contains('k-in-range')).to.be.true;
645
+ dispatchEvent(first.previousElementSibling!.previousElementSibling!, 'mouseenter');
646
+ await wait();
647
+ expect(first.previousElementSibling!.classList.contains('k-in-range')).to.be.true;
648
+ expect(first.nextElementSibling!.classList.contains('k-in-range')).to.be.false;
649
+ dispatchEvent(first.previousElementSibling!.previousElementSibling!, 'click');
650
+ await wait();
651
+ const value = instance.get('date')!;
652
+ expect(value).have.lengthOf(2);
653
+ expect(value[0] < value[1]).to.be.true;
654
+ });
655
+
656
+ it('select the same date', async () => {
657
+ // select the middle date
658
+ first.click();
659
+ first.click();
660
+ await wait();
661
+ const value1 = instance.get('date')!;
662
+ expect(value1).have.lengthOf(2);
663
+ expect(value1[0]).eql(value1[1]);
664
+ });
665
+
666
+ it('cross months', async () => {
667
+ first.click();
668
+ let second = content.querySelector('.k-datepicker-calendar-time-wrapper:nth-child(2) .k-calendar-item:nth-child(19)') as HTMLElement;
669
+ second.click();
670
+ await wait();
671
+ expect(instance.get('date')).have.lengthOf(2);
672
+ });
489
673
 
490
- // cancel all of range values and re-select
491
- select.click();
492
- await wait();
493
- // select the middle date
494
- first.click();
495
- dispatchEvent(first.previousElementSibling!.previousElementSibling!, 'click');
496
- await wait();
497
- first.click();
498
- dispatchEvent(first.previousElementSibling!.previousElementSibling!, 'click');
499
- expect(instance.get('date')).eql(value);
674
+ it('can select end date which is less than start date on selecting', async () => {
675
+ // hide firstly
676
+ document.body.click();
677
+ await wait();
678
+ instance.set('date', ['2025-08-01', '2025-08-02']);
679
+ await wait();
680
+ // show again
681
+ select.click();
682
+ await wait();
683
+ // select date 3
684
+ const first = content.querySelector('.k-calendar-item:not(.k-exceed):not(.k-active)') as HTMLElement;
685
+ first.click();
686
+ await wait();
500
687
 
501
- // range cross months
502
- select.click();
503
- await wait();
504
- first.click();
505
- let second = content.querySelector('.k-datepicker-calendar-time-wrapper:nth-child(2) .k-calendar-item:nth-child(19)') as HTMLElement;
506
- second.click();
507
- await wait();
508
- expect(instance.get('date')).have.lengthOf(2);
688
+ const inputInner = select.querySelector('.k-input-inner') as HTMLInputElement;
689
+ expect(inputInner.value).eql('2025-08-03 ~ 2025-08-02');
690
+ expect(instance.get('date')).eql(['2025-08-01', '2025-08-02']);
509
691
 
692
+ // should update value after hiding
693
+ document.body.click();
694
+ await wait();
695
+ expect(inputInner.value).eql('2025-08-02 ~ 2025-08-03');
696
+ expect(instance.get('date')).eql(['2025-08-02', '2025-08-03']);
697
+ });
510
698
  });
511
699
 
512
- it('datetime', async () => {
513
- const [instance, element] = mount(MultipleDemo);
700
+ describe('datetime', async () => {
701
+ let instance: RangeDemo;
702
+ let element: HTMLElement;
703
+ let datetime: HTMLElement;
514
704
 
515
- const [, select] = element.querySelectorAll<HTMLElement>('.k-datepicker');
516
- dispatchEvent(select, 'click');
517
- await wait();
518
- const content = getElement('.k-datepicker-content')!;
519
- dispatchEvent(content.querySelector('.k-calendar-item:nth-child(18)')!, 'click');
520
- await wait();
521
- dispatchEvent(content.querySelector('.k-datepicker-footer .k-btn')!, 'click');
522
- await wait();
523
- expect(instance.get('datetime')).have.lengthOf(1);
705
+ const dateString = dayjs(now).date(1).format('YYYY-MM-DD');
524
706
 
525
- // select the same datetime
526
- dispatchEvent(content.querySelector('.k-calendar-item:nth-child(18)')!, 'click');
527
- await wait();
528
- dispatchEvent(content.querySelector('.k-datepicker-footer .k-btn')!, 'click');
529
- await wait();
530
- expect(instance.get('datetime')).have.lengthOf(1);
707
+ function match(value: string | null, time: string) {
708
+ expect(value).to.eql(`${dateString} ${time}`);
709
+ }
531
710
 
532
- // select different time with the same date
533
- dispatchEvent(content.querySelector('.k-calendar-item:nth-child(18)')!, 'click');
534
- await wait();
535
- dispatchEvent(content.querySelector('.k-scroll-select-item')!, 'click');
536
- await wait();
537
- dispatchEvent(content.querySelector('.k-datepicker-footer .k-btn')!, 'click');
538
- await wait();
539
- expect(instance.get('datetime')).have.lengthOf(2);
711
+ async function show() {
712
+ datetime.click();
713
+ await wait();
714
+ const content = getElement('.k-datepicker-content')!;
715
+ const first = content.querySelector('.k-calendar-item:not(.k-exceed)') as HTMLElement;
716
+ first.click();
717
+ await wait();
540
718
 
541
- // change to time panel, and remove the selections, then click confirm ok
542
- dispatchEvent(content.querySelector('.k-calendar-item:nth-child(18)')!, 'click');
543
- await wait();
544
- instance.set('datetime', []);
545
- await wait();
546
- dispatchEvent(content.querySelector('.k-datepicker-footer .k-btn')!, 'click');
547
- await wait();
548
- expect(instance.get('datetime')).have.lengthOf(1);
719
+ return [content, first];
720
+ }
721
+
722
+ beforeEach(() => {
723
+ const result = mount(RangeDemo);
724
+ instance = result[0];
725
+ element = result[1];
726
+ datetime = element.querySelectorAll<HTMLElement>('.k-datepicker')[1];
727
+ });
728
+
729
+ it('basic', async () => {
730
+ const [content, first] = await show();
731
+
732
+ // should enable confirm button and show the first date string in input
733
+ const confirm = content.querySelector('.k-datepicker-footer .k-btn') as HTMLElement;
734
+ const inputInner = datetime.querySelector('.k-input-inner') as HTMLInputElement;
735
+ expect(confirm.classList.contains('k-disabled')).to.be.false;
736
+ match(inputInner.getAttribute('placeholder'), '00:00:00 ~');
737
+ match(inputInner.value, '00:00:00 ~');
738
+ expect(instance.get('time')).eql(null);
739
+
740
+ // select time
741
+ dispatchEvent(content.querySelector('.k-scroll-select-item')!, 'click');
742
+ await wait();
743
+ match(inputInner.getAttribute('placeholder'), '15:00:00 ~');
744
+ match(inputInner.value, '15:00:00 ~');
745
+ confirm.click();
746
+ await wait();
747
+ // should disable confirm button on first click
748
+ expect(confirm.classList.contains('k-disabled')).to.be.true;
749
+
750
+ // select the second datetime
751
+ const second = first.nextElementSibling as HTMLElement;
752
+ second.click();
753
+ await wait();
754
+ const endDateString = dayjs(now).date(2).format('YYYY-MM-DD');
755
+ expect(inputInner.getAttribute('placeholder')).eql(`${dateString} 15:00:00 ~ ${endDateString} 00:00:00`);
756
+ expect(inputInner.value).eql(`${dateString} 15:00:00 ~ ${endDateString} 00:00:00`);
757
+ expect(instance.get('time')).eql(null);
758
+ confirm.click();
759
+ await wait();
760
+ expect(instance.get('time')).eql([`${dateString} 15:00:00`, `${endDateString} 00:00:00`]);
761
+ });
762
+
763
+ it('skip select date and select time for the end value directly', async () => {
764
+ const [content] = await show();
765
+
766
+ const confirm = await clickConfirm(content);
767
+ // select time
768
+ dispatchEvent(content.querySelector('.k-scroll-select-item')!, 'click');
769
+ await wait();
770
+ confirm.click();
771
+ await wait();
772
+ expect(instance.get('time')).eql([`${dateString} 00:00:00`, `${dateString} 15:00:00`]);
773
+ });
774
+
775
+ it('can change date before click confirm button', async () => {
776
+ const [content, first] = await show();
777
+ const nextFirst = first.nextElementSibling as HTMLElement;
778
+ nextFirst.click();
779
+ await wait();
780
+ const inputInner = datetime.querySelector('.k-input-inner') as HTMLInputElement;
781
+ const dateString = dayjs(now).date(2).format('YYYY-MM-DD');
782
+ expect(inputInner.value).to.eql(`${dateString} 00:00:00 ~`);
783
+
784
+ const confirm = await clickConfirm(content);
785
+ const second = nextFirst.nextElementSibling as HTMLElement;
786
+ second.click();
787
+ await wait();
788
+ expect(inputInner.value).to.eql(`${dateString} 00:00:00 ~ ${getDateString(3)} 00:00:00`);
789
+ (second.nextElementSibling as HTMLElement).click();
790
+ await wait();
791
+ expect(inputInner.value).to.eql(`${dateString} 00:00:00 ~ ${getDateString(4)} 00:00:00`);
792
+
793
+ confirm.click();
794
+ await wait();
795
+ expect(inputInner.value).to.eql(`${dateString} 00:00:00 ~ ${getDateString(4)} 00:00:00`);
796
+ expect(instance.get('time')).to.eql([`${dateString} 00:00:00`, `${getDateString(4)} 00:00:00`]);
797
+ });
798
+
799
+ it('can select end date which is less than start date on selecting', async () => {
800
+ const [content, first] = await show();
801
+ const nextFirst = first.nextElementSibling as HTMLElement;
802
+ nextFirst.click();
803
+ await wait();
804
+
805
+ const inputInner = datetime.querySelector('.k-input-inner') as HTMLInputElement;
806
+ expect(inputInner.value).to.eql(`${getDateString(2)} 00:00:00 ~`);
807
+
808
+ // hide to reset the selected state
809
+ document.body.click();
810
+ await wait();
811
+ expect(inputInner.value).to.eql(``);
812
+ expect(instance.get('time')).to.be.null;
813
+
814
+ // show again
815
+ datetime.click();
816
+ await wait();
817
+ nextFirst.click();
818
+ await wait();
819
+ const confirm = await clickConfirm(content);
820
+ first.click();
821
+ await wait();
822
+ const a = `${getDateString(2)} 00:00:00`;
823
+ const b = `${getDateString(1)} 00:00:00`;
824
+ expect(inputInner.value).to.eql(`${a} ~ ${b}`);
825
+ expect(instance.get('time')).to.eql(null);
826
+
827
+ confirm.click();
828
+ await wait();
829
+ expect(instance.get('time')).to.eql([b, a]);
830
+ });
831
+
832
+ it('should reset position on clear value or set value to empty', async () => {
833
+ const a = `${getDateString(1)} 00:00:00`;
834
+ const b = `${getDateString(2)} 00:00:00`;
835
+ instance.set('time', [a, b]);
836
+ const [content, first] = await show();
837
+
838
+ // clear
839
+ dispatchEvent(datetime.querySelector('.k-select-clear')!, 'click');
840
+ await wait();
841
+ expect(instance.get('time')).eql(null);
842
+ await selectAgain();
843
+
844
+ // set time to null
845
+ datetime.click();
846
+ await wait();
847
+ instance.set('time', null);
848
+ await selectAgain();
849
+
850
+ // set time to empty array
851
+ datetime.click();
852
+ await wait();
853
+ instance.set<[]>('time', []);
854
+ await selectAgain();
855
+
856
+ async function selectAgain() {
857
+ // can select the datetime again
858
+ await wait();
859
+ first.click();
860
+ await wait();
861
+ const confirm = await clickConfirm(content);
862
+ (first.nextElementSibling as HTMLElement).click();
863
+ await wait();
864
+ confirm.click();
865
+ await wait();
866
+ expect(instance.get('time')).eql([a, b]);
867
+ }
868
+ });
869
+
870
+ it('should only auto hide after twice selection and the start and end datetime are already selected', async () => {
871
+ const [content, first] = await show();
872
+ const next = first.nextElementSibling as HTMLElement;
873
+ next.click();
874
+ await wait();
875
+ const confirm = await clickConfirm(content);
876
+ await wait();
877
+ _checkDisplay(true);
878
+
879
+ first.click();
880
+ await wait();
881
+ confirm.click();
882
+ await wait();
883
+ _checkDisplay(false);
884
+
885
+ const startDate = '2025-08-07 00:00:00';
886
+ const endDate = '2025-08-10 00:00:00'
887
+ const inputInner = datetime.querySelector('.k-input-inner') as HTMLInputElement;
888
+ const separatePos = `${dateString} 00:00:00 ~`.length;
889
+
890
+ await resetAndShow();
891
+ const newFirst = content.querySelector('.k-calendar-item:not(.k-exceed)') as HTMLElement;
892
+ newFirst.click();
893
+ await wait();
894
+ confirm.click();
895
+ await wait();
896
+ _checkDisplay(true);
897
+ expect(instance.get('time')).eql([startDate, endDate]);
898
+
899
+ // cancel the start time selection
900
+ document.body.click();
901
+ await wait();
902
+ expect(instance.get('time')).eql(['2025-08-01 00:00:00', startDate]);
903
+
904
+ // select from end position to start position
905
+ await resetAndShow();
906
+ newFirst.click();
907
+ await wait();
908
+ confirm.click();
909
+ await wait();
910
+ (newFirst.nextElementSibling as HTMLElement).click();
911
+ await wait();
912
+ _checkDisplay(true);
913
+ expect(instance.get('time')).eql([startDate, endDate]);
914
+ confirm.click();
915
+ await wait();
916
+ _checkDisplay(false);
917
+ expect(instance.get('time')).eql(['2025-08-01 00:00:00', '2025-08-02 00:00:00']);
918
+
919
+ // select the end position value then change to end position again
920
+ await resetAndShow();
921
+ newFirst.click();
922
+ await wait();
923
+ confirm.click();
924
+ await wait();
925
+ // change to the end position
926
+ setCursor(separatePos + 1);
927
+ datetime.click();
928
+ (newFirst.nextElementSibling as HTMLElement).click();
929
+ await wait();
930
+ _checkDisplay(true);
931
+ confirm.click();
932
+ // should not hide
933
+ await wait();
934
+ _checkDisplay(true);
935
+ // select the start position value
936
+ newFirst.click();
937
+ await wait();
938
+ confirm.click();
939
+ await wait();
940
+ _checkDisplay(false);
941
+ expect(instance.get('time')).eql(['2025-08-01 00:00:00', '2025-08-02 00:00:00']);
942
+
943
+ function _checkDisplay(isShow: boolean) {
944
+ checkDisplay(content, isShow);
945
+ }
946
+
947
+ function setCursor(pos: number) {
948
+ inputInner.focus();
949
+ inputInner.setSelectionRange(pos, pos);
950
+ }
951
+
952
+ async function resetAndShow() {
953
+ instance.set('time', [startDate, endDate]);
954
+ await wait();
955
+ setCursor(separatePos + 1);
956
+ datetime.click();
957
+ await wait();
958
+ }
959
+ });
549
960
  });
550
961
 
551
962
  it('year', async () => {
@@ -709,6 +1120,33 @@ describe('Datepicker', () => {
709
1120
  await wait();
710
1121
  expect(fn.callCount).to.eql(4);
711
1122
  });
1123
+
1124
+ it('should trigger change event once', async () => {
1125
+ const change = sinon.spy(() => console.log('change'));
1126
+ class Demo extends Component<{value: string}> {
1127
+ static template = `
1128
+ const {Datepicker} = this;
1129
+ <Datepicker range ev-$change:value={this.onChange} v-model="value" clearable />
1130
+ `;
1131
+ private Datepicker = Datepicker;
1132
+
1133
+ onChange() {
1134
+ change();
1135
+ }
1136
+ }
1137
+ const [instance, element] = mount(Demo);
1138
+ const input = element.querySelector<HTMLInputElement>('.k-input-inner')!;
1139
+
1140
+ input.click();
1141
+ await wait();
1142
+ const calendar = getElement('.k-datepicker-content')!;
1143
+ const [day1, day2] = calendar.querySelectorAll<HTMLElement>('.k-calendar-item:not(.k-exceed)');
1144
+ day1.click();
1145
+ await wait();
1146
+ day2.click();
1147
+ await wait();
1148
+ expect(change.callCount).to.eql(1);
1149
+ });
712
1150
  });
713
1151
 
714
1152
  it('should disable some time pickers', async () => {
@@ -724,6 +1162,7 @@ describe('Datepicker', () => {
724
1162
  await wait();
725
1163
  dispatchEvent(content.querySelector('.k-scroll-select:nth-child(3) .k-scroll-select-item')!, 'click');
726
1164
  (content.querySelector('.k-datepicker-footer .k-btn') as HTMLElement).click();
1165
+ await wait();
727
1166
 
728
1167
  expect(instance.get<string>('datetime2').split(' ')[1]).eql('00:00');
729
1168
  });