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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/components/.DS_Store +0 -0
  2. package/components/cascader/index.spec.ts +7 -6
  3. package/components/datepicker/basepicker.ts +26 -314
  4. package/components/datepicker/calendar.ts +3 -1
  5. package/components/datepicker/calendar.vdt +5 -2
  6. package/components/datepicker/dayjs.ts +2 -16
  7. package/components/datepicker/demos/multiple.md +5 -0
  8. package/components/datepicker/demos/yearMonth.md +2 -8
  9. package/components/datepicker/helpers.ts +5 -7
  10. package/components/datepicker/index.md +1 -2
  11. package/components/datepicker/index.spec.ts +551 -139
  12. package/components/datepicker/index.ts +16 -33
  13. package/components/datepicker/index.vdt +41 -35
  14. package/components/datepicker/shortcuts.ts +1 -1
  15. package/components/datepicker/styles.ts +27 -18
  16. package/components/datepicker/useConfirm.ts +82 -0
  17. package/components/datepicker/useDisabled.ts +29 -31
  18. package/components/datepicker/useFormats.ts +8 -4
  19. package/components/datepicker/useHighlight.ts +81 -0
  20. package/components/datepicker/useKeyboards.ts +2 -1
  21. package/components/datepicker/useMergeRange.ts +12 -12
  22. package/components/datepicker/useMonths.ts +6 -3
  23. package/components/datepicker/usePanel.ts +19 -19
  24. package/components/datepicker/useShowDate.ts +21 -41
  25. package/components/datepicker/useStatus.ts +34 -15
  26. package/components/datepicker/useValue.ts +43 -72
  27. package/components/datepicker/useValueBase.ts +309 -0
  28. package/components/datepicker/useWeeks.ts +1 -1
  29. package/components/datepicker/useYears.ts +7 -3
  30. package/components/descriptions/.DS_Store +0 -0
  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/input/index.spec.ts +42 -0
  36. package/components/input/index.ts +8 -0
  37. package/components/input/index.vdt +3 -4
  38. package/components/input/useAutoWidth.ts +19 -1
  39. package/components/menu/.DS_Store +0 -0
  40. package/components/menu/demos/.DS_Store +0 -0
  41. package/components/scrollSelect/useMouseEvents.ts +5 -4
  42. package/components/select/base.ts +3 -2
  43. package/components/select/base.vdt +2 -1
  44. package/components/select/demos/creatable.md +2 -2
  45. package/components/select/index.md +1 -1
  46. package/components/select/index.spec.ts +107 -34
  47. package/components/select/option.ts +2 -1
  48. package/components/select/select.ts +1 -0
  49. package/components/select/styles.ts +3 -1
  50. package/components/select/useInput.ts +5 -9
  51. package/components/table/.DS_Store +0 -0
  52. package/components/table/index.spec.ts +69 -1
  53. package/components/table/useStickyHeader.ts +1 -1
  54. package/components/timepicker/index.spec.ts +145 -27
  55. package/components/timepicker/panelPicker.ts +10 -4
  56. package/components/timepicker/panelPicker.vdt +3 -5
  57. package/components/timepicker/styles.ts +1 -0
  58. package/components/timepicker/useConfirm.ts +33 -0
  59. package/components/timepicker/useDefaultValue.ts +30 -0
  60. package/components/timepicker/useDisabled.ts +17 -4
  61. package/components/timepicker/useFormats.ts +1 -1
  62. package/components/timepicker/useValue.ts +22 -19
  63. package/components/tour/.DS_Store +0 -0
  64. package/components/tour/index.spec.ts +1 -1
  65. package/components/virtualList/.DS_Store +0 -0
  66. package/components/virtualList/demos/.DS_Store +0 -0
  67. package/es/components/cascader/index.spec.js +18 -19
  68. package/es/components/datepicker/basepicker.d.ts +6 -27
  69. package/es/components/datepicker/basepicker.js +23 -268
  70. package/es/components/datepicker/calendar.d.ts +4 -2
  71. package/es/components/datepicker/dayjs.d.ts +2 -13
  72. package/es/components/datepicker/helpers.d.ts +3 -2
  73. package/es/components/datepicker/helpers.js +2 -3
  74. package/es/components/datepicker/index.d.ts +21 -29
  75. package/es/components/datepicker/index.js +22 -32
  76. package/es/components/datepicker/index.spec.js +1333 -578
  77. package/es/components/datepicker/index.vdt.js +39 -38
  78. package/es/components/datepicker/shortcuts.d.ts +1 -1
  79. package/es/components/datepicker/styles.d.ts +7 -2
  80. package/es/components/datepicker/styles.js +10 -15
  81. package/es/components/datepicker/useConfirm.d.ts +6 -0
  82. package/es/components/datepicker/useConfirm.js +65 -0
  83. package/es/components/datepicker/useDisabled.d.ts +5 -3
  84. package/es/components/datepicker/useDisabled.js +22 -27
  85. package/es/components/datepicker/useFormats.d.ts +2 -2
  86. package/es/components/datepicker/useFormats.js +6 -2
  87. package/es/components/datepicker/useHighlight.d.ts +14 -0
  88. package/es/components/datepicker/useHighlight.js +60 -0
  89. package/es/components/datepicker/useKeyboards.js +2 -1
  90. package/es/components/datepicker/useMergeRange.d.ts +1 -1
  91. package/es/components/datepicker/useMergeRange.js +11 -16
  92. package/es/components/datepicker/useMonths.js +5 -3
  93. package/es/components/datepicker/usePanel.d.ts +1 -10
  94. package/es/components/datepicker/usePanel.js +19 -32
  95. package/es/components/datepicker/useShowDate.d.ts +1 -1
  96. package/es/components/datepicker/useShowDate.js +15 -40
  97. package/es/components/datepicker/useStatus.js +33 -16
  98. package/es/components/datepicker/useValue.d.ts +11 -6
  99. package/es/components/datepicker/useValue.js +49 -69
  100. package/es/components/datepicker/useValueBase.d.ts +28 -0
  101. package/es/components/datepicker/useValueBase.js +277 -0
  102. package/es/components/datepicker/useYears.js +6 -3
  103. package/es/components/dropdown/dropdown.d.ts +1 -0
  104. package/es/components/dropdown/dropdown.js +7 -4
  105. package/es/components/input/index.d.ts +2 -0
  106. package/es/components/input/index.js +6 -0
  107. package/es/components/input/index.spec.js +45 -0
  108. package/es/components/input/index.vdt.js +4 -3
  109. package/es/components/input/useAutoWidth.d.ts +2 -0
  110. package/es/components/input/useAutoWidth.js +19 -1
  111. package/es/components/scrollSelect/useMouseEvents.js +5 -4
  112. package/es/components/select/base.d.ts +1 -1
  113. package/es/components/select/base.js +3 -2
  114. package/es/components/select/base.vdt.js +4 -3
  115. package/es/components/select/index.spec.js +158 -84
  116. package/es/components/select/option.js +2 -1
  117. package/es/components/select/select.js +2 -1
  118. package/es/components/select/styles.d.ts +79 -0
  119. package/es/components/select/styles.js +1 -0
  120. package/es/components/select/useInput.d.ts +1 -1
  121. package/es/components/select/useInput.js +4 -4
  122. package/es/components/table/index.spec.js +84 -6
  123. package/es/components/table/useStickyHeader.js +1 -1
  124. package/es/components/timepicker/index.spec.js +298 -128
  125. package/es/components/timepicker/panelPicker.d.ts +21 -16
  126. package/es/components/timepicker/panelPicker.js +7 -4
  127. package/es/components/timepicker/panelPicker.vdt.js +5 -9
  128. package/es/components/timepicker/selectPicker.d.ts +4 -3
  129. package/es/components/timepicker/styles.js +1 -1
  130. package/es/components/timepicker/useConfirm.d.ts +6 -0
  131. package/es/components/timepicker/useConfirm.js +19 -0
  132. package/es/components/timepicker/useDefaultValue.d.ts +4 -0
  133. package/es/components/timepicker/useDefaultValue.js +27 -0
  134. package/es/components/timepicker/useDisabled.d.ts +6 -3
  135. package/es/components/timepicker/useDisabled.js +13 -4
  136. package/es/components/timepicker/useFormats.d.ts +1 -1
  137. package/es/components/timepicker/useValue.d.ts +13 -8
  138. package/es/components/timepicker/useValue.js +14 -15
  139. package/es/components/tour/index.spec.js +1 -1
  140. package/es/index.d.ts +2 -2
  141. package/es/index.js +2 -2
  142. package/es/site/data/components/datepicker/demos/multiple/index.d.ts +1 -0
  143. package/es/site/data/components/datepicker/demos/multiple/index.js +2 -1
  144. package/es/site/data/components/datepicker/demos/multiple/react.d.ts +1 -0
  145. package/es/site/data/components/datepicker/demos/multiple/react.js +13 -2
  146. package/es/site/data/components/datepicker/demos/yearMonth/index.d.ts +0 -2
  147. package/es/site/data/components/datepicker/demos/yearMonth/index.js +1 -3
  148. package/es/site/data/components/datepicker/demos/yearMonth/react.d.ts +0 -2
  149. package/es/site/data/components/datepicker/demos/yearMonth/react.js +1 -21
  150. package/es/site/data/components/select/demos/creatable/react.js +2 -2
  151. package/es/site/data/components/select/demos/searchable/index.js +1 -1
  152. package/es/site/data/components/select/demos/searchable/react.js +1 -1
  153. package/es/site/data/components/tour/demos/customText/index.d.ts +19 -6
  154. package/es/site/data/components/tour/demos/customText/index.js +18 -17
  155. package/es/site/data/components/tour/demos/customText/react.d.ts +20 -6
  156. package/es/site/data/components/tour/demos/customText/react.js +31 -27
  157. package/index.ts +2 -2
  158. package/package.json +2 -2
  159. package/styles/.DS_Store +0 -0
  160. package/components/datepicker/demos/nowrap.md +0 -35
  161. package/components/datepicker/usePosition.ts +0 -169
  162. package/es/components/datepicker/usePosition.d.ts +0 -10
  163. package/es/components/datepicker/usePosition.js +0 -166
  164. package/es/site/data/components/datepicker/demos/nowrap/index.d.ts +0 -10
  165. package/es/site/data/components/datepicker/demos/nowrap/index.js +0 -19
  166. package/es/site/data/components/datepicker/demos/nowrap/react.d.ts +0 -10
  167. package/es/site/data/components/datepicker/demos/nowrap/react.js +0 -49
  168. package/es/site/data/components/tour/demos/customButtons/index.d.ts +0 -33
  169. package/es/site/data/components/tour/demos/customButtons/index.js +0 -55
  170. package/es/site/data/components/tour/demos/customButtons/react.d.ts +0 -33
  171. package/es/site/data/components/tour/demos/customButtons/react.js +0 -99
@@ -206,6 +206,9 @@ describe('Select', () => {
206
206
  const [instance, element] = mount(CreatableDemo);
207
207
 
208
208
  const input = element.querySelector('.k-input-inner') as HTMLInputElement;
209
+
210
+ expect(instance.get('day')).to.be.null;
211
+
209
212
  input.click();
210
213
  await wait();
211
214
  input.value = 'xxx';
@@ -213,38 +216,82 @@ describe('Select', () => {
213
216
  await wait();
214
217
  const dropdown = getElement('.k-select-menu')!;
215
218
  expect(dropdown.innerHTML).to.matchSnapshot();
216
- // select
219
+
220
+ // check the created option appears in dropdown
221
+ const createOption = dropdown.querySelector('.k-select-option');
222
+ expect(createOption).to.exist;
223
+ expect(createOption!.textContent).to.contain('xxx');
224
+
225
+ // press enter to select the custom option
217
226
  dispatchEvent(document, 'keydown', {keyCode: 13});
218
227
  await wait();
219
228
  expect(instance.get('day')).to.eql('xxx');
229
+ expect(input.value).to.eql('xxx');
220
230
 
221
- // open again
231
+ // reopen dropdown
222
232
  input.click();
223
233
  await wait();
224
234
  expect(element.innerHTML).to.matchSnapshot();
225
235
  expect(dropdown.innerHTML).to.matchSnapshot();
226
-
227
- // input again
236
+
237
+ // input another custom option
228
238
  input.value = 'yyy';
229
239
  dispatchEvent(input, 'input');
230
240
  await wait();
231
241
  expect(element.innerHTML).to.matchSnapshot();
232
242
  expect(dropdown.innerHTML).to.matchSnapshot();
233
243
 
234
- // discard
244
+ const newCreateOption = dropdown.querySelector('.k-select-option');
245
+ expect(newCreateOption).to.exist;
246
+ expect(newCreateOption!.textContent).to.contain('yyy');
247
+
248
+ // click outside to cancel selection
235
249
  dispatchEvent(document, 'click');
236
250
  await wait();
237
251
  expect(element.innerHTML).to.matchSnapshot();
238
- expect(instance.get('day')).to.eql('xxx');
252
+ expect(instance.get('day')).to.eql('xxx'); // should keep the original value
253
+ expect(input.value).to.eql('xxx'); // should restore the original value
254
+
255
+ // test multiple creatable
256
+ const [, multipleInput] = element.querySelectorAll<HTMLInputElement>('.k-input-inner');
257
+ expect(instance.get('days')).to.eql([]);
258
+
259
+ multipleInput.click();
260
+ await wait();
261
+ multipleInput.value = 'custom1';
262
+ dispatchEvent(multipleInput, 'input');
263
+ await wait();
264
+
265
+ // press enter to create and select the first custom option
266
+ dispatchEvent(document, 'keydown', {keyCode: 13});
267
+ await wait();
268
+ expect(instance.get('days')).to.include('custom1');
269
+ expect(multipleInput.value).to.eql('custom1');
270
+
271
+ // input the same option again
272
+ dispatchEvent(document, 'keydown', {keyCode: 13});
273
+ await wait();
274
+ expect(instance.get('days')).to.eql([]);
275
+ expect(multipleInput.value).to.eql('custom1');
276
+
277
+ // test select original options
278
+ multipleInput.value = 'Monday';
279
+ dispatchEvent(multipleInput, 'input');
280
+ await wait();
281
+ const multipleDropdown = getElement('.k-select-menu')!;
282
+ const mondayOption = multipleDropdown.querySelector('.k-select-option') as HTMLElement;
283
+ expect(mondayOption.textContent).to.eql('星期一');
284
+ mondayOption.click();
285
+ await wait();
286
+ expect(instance.get('days')).to.include('Monday');
239
287
  });
240
288
 
241
289
  it('keepKeywords', async () => {
242
- // 创建一个测试组件,包含keepKeywords功能
243
290
  class KeepKeywordsDemo extends Component<{days: string[]}> {
244
291
  static template = `
245
292
  const {Select, Option} = this;
246
293
  <div>
247
- <Select v-model="days" filterable multiple creatable keepKeywords>
294
+ <Select v-model="days" filterable multiple creatable keepKeywords={false}>
248
295
  <Option value="Monday">星期一</Option>
249
296
  <Option value="Tuesday">星期二</Option>
250
297
  <Option value="Wednesday">星期三</Option>
@@ -263,50 +310,50 @@ describe('Select', () => {
263
310
  const [instance, element] = mount(KeepKeywordsDemo);
264
311
  const input = element.querySelector('.k-input-inner') as HTMLInputElement;
265
312
 
266
- // 1. 输入自定义选项 "custom1"
313
+ // input custom option "custom1"
267
314
  input.click();
268
315
  await wait();
269
316
  input.value = 'custom1';
270
317
  dispatchEvent(input, 'input');
271
318
  await wait();
272
319
 
273
- // 验证创建的选项出现在dropdown
320
+ // check the created option appears in dropdown
274
321
  const dropdown = getElement('.k-select-menu')!;
275
322
  expect(dropdown.innerHTML).to.contain('custom1');
276
323
 
277
- // 2. 按回车创建并选中
324
+ // press enter to create and select
278
325
  dispatchEvent(document, 'keydown', {keyCode: 13});
279
326
  await wait();
280
327
 
281
- // 验证选项被选中,且输入框被清空
328
+ // check the option is selected, and the input is cleared
282
329
  expect(instance.get('days')).to.eql(['custom1']);
283
- expect(input.value).to.eql(''); // keepKeywords=true时应该清空输入框
330
+ expect(input.value).to.eql('');
284
331
 
285
- // 3. 再次输入相同的选项 "custom1"
332
+ // input the same option "custom1" again
286
333
  input.value = 'custom1';
287
334
  dispatchEvent(input, 'input');
288
335
  await wait();
289
336
 
290
- // 4. 再次按回车
337
+ // press enter again
291
338
  dispatchEvent(document, 'keydown', {keyCode: 13});
292
339
  await wait();
293
340
 
294
- // 验证选项仍然被选中(不会被取消选中),且输入框被清空
295
- expect(instance.get('days')).to.eql(['custom1']); // 应该保持选中状态
296
- expect(input.value).to.eql(''); // 输入框应该被清空
341
+ // check the option is still selected (not be unselected), and the input is cleared
342
+ expect(instance.get('days')).to.eql(['custom1']); // should be selected
343
+ expect(input.value).to.eql(''); // should be cleared
297
344
 
298
- // 5. 输入另一个自定义选项 "custom2"
345
+ // input another custom option "custom2"
299
346
  input.value = 'custom2';
300
347
  dispatchEvent(input, 'input');
301
348
  await wait();
302
349
  dispatchEvent(document, 'keydown', {keyCode: 13});
303
350
  await wait();
304
351
 
305
- // 验证两个选项都被选中
352
+ // check two options are selected
306
353
  expect(instance.get('days')).to.eql(['custom1', 'custom2']);
307
354
  expect(input.value).to.eql('');
308
355
 
309
- // 6. 测试原有选项的正常行为
356
+ // test the normal behavior of original options
310
357
  input.click();
311
358
  await wait();
312
359
  const mondayOption = dropdown.querySelector('[data-value="Monday"]') as HTMLElement;
@@ -315,7 +362,7 @@ describe('Select', () => {
315
362
  await wait();
316
363
  expect(instance.get('days')).to.include('Monday');
317
364
 
318
- // 再次点击应该能取消选中(原有选项不受keepKeywords影响)
365
+ // click again should be unselected (original options are not affected by keepKeywords)
319
366
  mondayOption.click();
320
367
  await wait();
321
368
  expect(instance.get('days')).to.not.include('Monday');
@@ -383,21 +430,47 @@ describe('Select', () => {
383
430
  });
384
431
 
385
432
  it('Searchable with multiple should show correct initial checkbox state', async () => {
386
- const [instance, element] = mount(SearchableDemo);
433
+ class Demo extends Component {
434
+ static template = `
435
+ const {Select, Option} = this;
436
+ <Select v-model="days" searchable multiple>
437
+ <Option value="Monday" disabled>星期一</Option>
438
+ <Option value="Tuesday">星期二</Option>
439
+ <Option value="Wednesday">星期三</Option>
440
+ <Option value="Thursday">星期四</Option>
441
+ <Option value="Friday">星期五</Option>
442
+ <Option value="Saturday">星期六</Option>
443
+ <Option value="Sunday">星期天</Option>
444
+ <b:values args="[value]">
445
+ <div class="k-value">
446
+ 已选择{value.length}项 / 共7项
447
+ </div>
448
+ </b:values>
449
+ </Select>
450
+ `;
451
+ static defaults() {
452
+ return {
453
+ days: ['Tuesday']
454
+ }
455
+ }
456
+ private Tooltip = Tooltip;
457
+ private Select = Select;
458
+ private Option = Option;
459
+ }
460
+
461
+ const [instance, element] = mount(Demo as any);
387
462
 
388
- // 验证初始值
389
463
  expect(instance.get('days')).to.eql(['Tuesday']);
390
464
 
391
- // 第一次打开dropdown,检查初始状态
392
- const [, select] = element.querySelectorAll<HTMLElement>('.k-select');
393
- select.click();
465
+ // first open dropdown, check initial state
466
+ element.click();
394
467
  await wait();
395
468
 
396
469
  const dropdown = getElement('.k-select-menu')!;
397
470
  const checkboxes = dropdown.querySelectorAll<HTMLInputElement>('.k-checkbox input[type="checkbox"]');
398
471
  const options = dropdown.querySelectorAll<HTMLElement>('.k-select-option');
399
472
 
400
- // 找到Tuesday选项对应的checkbox
473
+ // find the checkbox of Tuesday option
401
474
  let tuesdayCheckbox: HTMLInputElement | null = null;
402
475
  let tuesdayOption: HTMLElement | null = null;
403
476
 
@@ -408,21 +481,21 @@ describe('Select', () => {
408
481
  }
409
482
  });
410
483
 
411
- // 验证Tuesday的checkbox应该被选中
484
+ // check the checkbox of Tuesday should be checked
412
485
  expect(tuesdayCheckbox).to.exist;
413
486
  expect(tuesdayCheckbox!.checked).to.be.true;
414
487
 
415
- // 验证Tuesday选项应该有active样式
488
+ // check the Tuesday option should have active style
416
489
  expect(tuesdayOption).to.exist;
417
490
  expect(tuesdayOption!.className).to.include('k-active');
418
491
 
419
- // 关闭dropdown
492
+ // close dropdown
420
493
  const [cancel] = dropdown.querySelectorAll<HTMLElement>('.k-select-footer .k-btn');
421
494
  cancel.click();
422
495
  await wait();
423
496
 
424
- // 再次打开dropdown,验证状态仍然正确
425
- select.click();
497
+ // reopen dropdown, check the state is still correct
498
+ element.click();
426
499
  await wait();
427
500
 
428
501
  const dropdown2 = getElement('.k-select-menu')!;
@@ -439,7 +512,7 @@ describe('Select', () => {
439
512
  }
440
513
  });
441
514
 
442
- // 验证第二次打开时状态依然正确
515
+ // check the state is still correct when reopen
443
516
  expect(tuesdayCheckbox2!.checked).to.be.true;
444
517
  expect(tuesdayOption2!.className).to.include('k-active');
445
518
  });
@@ -40,7 +40,8 @@ export class Option extends Component<OptionProps> {
40
40
  } else {
41
41
  let values = select.get('value');
42
42
 
43
- if (keepKeywords && isCreated && Array.isArray(values) && values.includes(value)) {
43
+ if (!keepKeywords && isCreated && Array.isArray(values) && values.includes(value)) {
44
+ select.resetKeywords();
44
45
  return;
45
46
  }
46
47
 
@@ -44,6 +44,7 @@ const typeDefs: Required<TypeDefs<SelectProps>> = {
44
44
  const defaults = (): Partial<SelectProps> => ({
45
45
  ...BaseSelect.defaults(),
46
46
  labelMap: new Map(),
47
+ keepKeywords: true,
47
48
  });
48
49
 
49
50
  export class Select<
@@ -5,7 +5,7 @@ import '../../styles/global';
5
5
  import { cache } from '../utils';
6
6
 
7
7
  type SizeStyles = {
8
- padding?: string,
8
+ padding: string,
9
9
  height: string,
10
10
  fontSize: string,
11
11
  }
@@ -118,6 +118,8 @@ setDefault(() => {
118
118
  makeGroupStyles?.clearCache();
119
119
  });
120
120
 
121
+ export { select }
122
+
121
123
  export const makeStyles = cache(function makeStyles(k: string) {
122
124
  return css`
123
125
  display: inline-flex;
@@ -11,13 +11,9 @@ import {
11
11
  } from 'intact';
12
12
  import {useState, State} from '../../hooks/useState';
13
13
  import type {Select, SelectProps} from './select';
14
- import {Option, OptionProps} from './option';
15
- import {OptionGroup, OptionGroupProps} from './group';
16
- import {isNullOrUndefined, EMPTY_OBJ, isStringOrNumber} from 'intact-shared';
17
- import {getTextByChildren, mapChildren, isComponentVNode} from '../utils';
18
14
  import type {Input} from '../input';
19
15
 
20
- export function useInput(resetKeywords: (keywords: State<string>) => void) {
16
+ export function useInput(resetKeywords: () => void) {
21
17
  const component = useInstance() as Select;
22
18
  const keywords = useState('');
23
19
  const inputRef = createRef<Input>();
@@ -50,9 +46,9 @@ export function useInput(resetKeywords: (keywords: State<string>) => void) {
50
46
  component.on('$changed:show', show => {
51
47
  if (show) {
52
48
  focusInput();
53
- resetKeywords(keywords);
49
+ resetKeywords();
54
50
  } else if (component.get('multiple')) {
55
- resetKeywords(keywords);
51
+ resetKeywords();
56
52
  }
57
53
  });
58
54
  component.on('$changed:value', () => {
@@ -63,8 +59,8 @@ export function useInput(resetKeywords: (keywords: State<string>) => void) {
63
59
  * don't reset keywords on multiple mode for continue selection
64
60
  * https://github.com/ksc-fe/kpc/issues/983
65
61
  */
66
- if (keepKeywords) {
67
- resetKeywords(keywords);
62
+ if (!keepKeywords) {
63
+ resetKeywords();
68
64
  }
69
65
  }
70
66
  });
Binary file
@@ -496,7 +496,6 @@ describe('Table', () => {
496
496
  checkbox.click();
497
497
  await wait();
498
498
  expect(element.innerHTML).to.matchSnapshot();
499
- debugger;
500
499
  expect(table.getCheckedData()).to.have.lengthOf(8);
501
500
 
502
501
  const arrow = element.querySelector('.k-table-arrow') as HTMLElement;
@@ -723,4 +722,73 @@ describe('Table', () => {
723
722
  expect(spy.callCount).to.eql(5);
724
723
  expect(spy.lastCall.lastArg).to.eql({value: 2, limit: 10});
725
724
  });
725
+
726
+ it('fixHeader with Affix header scroll sync', async () => {
727
+ interface Props {
728
+ data: any[]
729
+ fixHeader: boolean | number
730
+ virtual: boolean
731
+ stickScrollbar: boolean | number
732
+ }
733
+
734
+ class Demo extends Component<Props> {
735
+ static template = `
736
+ const {Table, TableColumn} = this;
737
+ const {data, fixHeader, virtual, stickScrollbar} = this.get();
738
+ <Table data={data} fixHeader={fixHeader} virtual={virtual} stickScrollbar={stickScrollbar} ref="table">
739
+ <TableColumn fixed="left" key="name" title="Name" width="200" />
740
+ <TableColumn key="column1" title="Column1" width="300" />
741
+ <TableColumn key="column2" title="Column2" width="300" />
742
+ <TableColumn key="column3" title="Column3" width="300" />
743
+ <TableColumn fixed="right" key="action" title="Action" width="200" />
744
+ </Table>
745
+ `;
746
+
747
+ static defaults() {
748
+ return {
749
+ data: Array.from({length: 10}, (_, i) => ({
750
+ name: `Name ${i}`,
751
+ column1: `Column1 ${i}`,
752
+ column2: `Column2 ${i}`,
753
+ column3: `Column3 ${i}`,
754
+ action: `Action ${i}`
755
+ })),
756
+ fixHeader: 200,
757
+ virtual: false,
758
+ stickScrollbar: false
759
+ };
760
+ }
761
+
762
+ private Table = Table;
763
+ private TableColumn = TableColumn;
764
+ }
765
+
766
+ const [instance, element] = mount(Demo);
767
+
768
+ // Test 1: fixHeader only - scroll left 50px
769
+ await wait();
770
+ const scrollContainer = element.querySelector('.k-table-wrapper') as HTMLElement;
771
+ scrollContainer.scrollLeft = 50;
772
+ await wait(100);
773
+ const affixWrapper1 = element.querySelector('.k-table-affix-header .k-affix-wrapper') as HTMLElement;
774
+ expect(affixWrapper1.scrollLeft).to.eql(50);
775
+
776
+ // Test 2: fixHeader + virtual - scroll left 50px more (total 100px)
777
+ instance.set('virtual', true);
778
+ await wait();
779
+ scrollContainer.scrollLeft = 100;
780
+ await wait(100);
781
+
782
+ const affixWrapper2 = element.querySelector('.k-table-affix-header .k-affix-wrapper') as HTMLElement;
783
+ expect(affixWrapper2.scrollLeft).to.eql(100);
784
+
785
+ // Test 3: stickScrollbar + fixHeader - scroll right 50px (back to 50px)
786
+ instance.set('stickScrollbar', true);
787
+ await wait();
788
+ scrollContainer.scrollLeft = 50;
789
+ await wait(100);
790
+
791
+ const affixWrapper3 = element.querySelector('.k-table-affix-header .k-affix-wrapper') as HTMLElement;
792
+ expect(affixWrapper3.scrollLeft).to.eql(50);
793
+ });
726
794
  });
@@ -22,7 +22,7 @@ export function useStickyHeader(callbacks: ScrollCallback[]) {
22
22
 
23
23
  // when the scroll element scroll horizontally, scroll the sticky header too
24
24
  callbacks.push(scrollLeft => {
25
- if (isNull(stickHeader.value)) return;
25
+ if (isNull(stickHeader.value) && !instance.get('fixHeader')) return;
26
26
 
27
27
  const affixHeadWrapper = headRef.value!.parentElement as HTMLElement;
28
28
  affixHeadWrapper.scrollLeft = scrollLeft;
@@ -8,7 +8,6 @@ import {Timepicker} from 'kpc';
8
8
  import {Component} from 'intact';
9
9
 
10
10
  describe('Timepicker', () => {
11
-
12
11
  afterEach(async () => {
13
12
  unmount();
14
13
  await wait(500);
@@ -19,10 +18,18 @@ describe('Timepicker', () => {
19
18
  const [instance, element] = mount(BasicDemo);
20
19
 
21
20
  const [picker1, picker2] = element.querySelectorAll('.k-select') as NodeListOf<HTMLElement>;
21
+ const inputInner = picker1.querySelector('.k-input-inner') as HTMLInputElement;
22
+
23
+ expect(inputInner.value).eql('');
22
24
  picker1.click();
23
25
  await wait(500);
24
- let dropdown = getElement('.k-time-content')!;
26
+ expect(inputInner.value).eql('');
27
+
28
+ const dropdown = getElement('.k-time-content')!;
29
+ const ok = dropdown.querySelector('.k-btn') as HTMLElement;
30
+ expect(ok.classList.contains('k-disabled')).eql(true);
25
31
  expect(dropdown.innerHTML).to.matchSnapshot();
32
+
26
33
  const next = dropdown.querySelector('.k-scroll-select-item:nth-child(11)') as HTMLElement;
27
34
  next.click();
28
35
  await wait();
@@ -32,7 +39,6 @@ describe('Timepicker', () => {
32
39
  await wait();
33
40
  expect(instance.get('time')).to.be.null;
34
41
  expect(dropdown.innerHTML).to.matchSnapshot();
35
- const ok = dropdown.querySelector('.k-btn') as HTMLElement;
36
42
  ok.click();
37
43
  await wait(500);
38
44
  expect(instance.get('time')).to.eql('02:00:00');
@@ -43,27 +49,56 @@ describe('Timepicker', () => {
43
49
  await wait(500);
44
50
  expect(dropdown.innerHTML).to.matchSnapshot();
45
51
 
52
+ // should reset show value on hiding
53
+ const activeHour = dropdown.querySelector('.k-scroll-select-item.k-active') as HTMLElement;
54
+ dispatchEvent(activeHour.nextElementSibling!, 'click');
55
+ await wait();
56
+ expect(inputInner.value).eql('04:03:03');
57
+ expect(instance.get('time')).eql('03:03:03');
58
+ document.body.click();
59
+ await wait();
60
+ expect(inputInner.value).eql('03:03:03');
61
+ expect(instance.get('time')).eql('03:03:03');
62
+ });
63
+
64
+ it('multipe time', async function() {
65
+ const [instance, element] = mount(BasicDemo);
66
+ const [picker1, picker2] = element.querySelectorAll('.k-select') as NodeListOf<HTMLElement>;
67
+
46
68
  // multiple
47
69
  picker2.click();
48
- await wait(500);
49
- dropdown = getElement('.k-time-content')!;
50
- dropdown.querySelector<HTMLElement>('.k-scroll-select-item:nth-child(11)')!.click();
70
+ await wait();
71
+ let dropdown = getElement('.k-time-content')!;
51
72
  const ok2 = dropdown.querySelector('.k-btn') as HTMLElement;
73
+ expect(ok2.classList.contains('k-disabled')).eql(false);
74
+
75
+ dropdown.querySelector<HTMLElement>('.k-scroll-select-item:nth-child(11)')!.click();
76
+ await wait();
77
+ const inputInner = picker2.querySelector('.k-input-inner') as HTMLInputElement;
78
+ expect(inputInner.value).eql('01:00:00');
79
+ expect(instance.get('timeArray')).eql([]);
80
+
52
81
  ok2.click();
53
- dropdown.querySelector<HTMLElement>('.k-scroll-select-item:nth-child(12)')!.click();
82
+ await wait();
83
+ expect(instance.get('timeArray')).eql(['01:00:00']);
84
+
85
+ dropdown.querySelector<HTMLElement>('.k-scroll-select-item:nth-child(11)')!.click();
86
+ await wait();
54
87
  ok2.click();
55
88
  await wait();
56
89
  expect(instance.get('timeArray')).to.eql(['01:00:00', '02:00:00']);
90
+ expect(ok2.classList.contains('k-disabled')).eql(false);
91
+
57
92
  // click the same time will do nothing
58
93
  ok2.click();
59
94
  await wait();
60
95
  expect(instance.get('timeArray')).to.eql(['01:00:00', '02:00:00']);
96
+
61
97
  // remove one value
62
98
  const [, close] = picker2.querySelectorAll<HTMLElement>('.k-tag-close');
63
99
  close.click();
64
100
  await wait();
65
101
  expect(instance.get('timeArray')).to.eql(['01:00:00']);
66
- expect(dropdown.innerHTML).to.matchSnapshot();
67
102
 
68
103
  // clear
69
104
  picker2.querySelector<HTMLElement>('.k-select-clear')!.click();
@@ -79,24 +114,107 @@ describe('Timepicker', () => {
79
114
  expect(dropdown.innerHTML).to.matchSnapshot();
80
115
  });
81
116
 
82
- it('range', async () => {
83
- const [instance, element] = mount(RangeDemo);
117
+ describe('range', () => {
118
+ it('basic', async () => {
119
+ const [instance, element] = mount(RangeDemo);
84
120
 
85
- const picker = element.querySelector('.k-select') as HTMLElement;
86
- picker.click();
87
- await wait(500);
88
- const dropdown = getElement('.k-time-content')!;
89
- expect(dropdown.innerHTML).to.matchSnapshot();
90
- const [start, end] = dropdown.querySelectorAll<HTMLElement>('.k-datepicker-calendar-wrapper');
91
- (start.querySelector('.k-active')!.nextElementSibling as HTMLElement).click();
92
- await wait();
93
- expect(dropdown.innerHTML).to.matchSnapshot();
94
- (end.querySelector('.k-active')!.nextElementSibling!.nextElementSibling as HTMLElement).click();
95
- await wait();
96
- expect(dropdown.innerHTML).to.matchSnapshot();
97
- dropdown.querySelector<HTMLElement>('.k-btn')!.click();
98
- await wait();
99
- expect(instance.get('time')).to.eql(['01:00:00', '01:59:59']);
121
+ const picker = element.querySelector('.k-select') as HTMLElement;
122
+ picker.click();
123
+ await wait(500);
124
+ const dropdown = getElement('.k-time-content')!;
125
+ expect(dropdown.innerHTML).to.matchSnapshot();
126
+ const [start, end] = dropdown.querySelectorAll<HTMLElement>('.k-datepicker-calendar-wrapper');
127
+ (start.querySelector('.k-active')!.nextElementSibling as HTMLElement).click();
128
+ await wait();
129
+ expect(dropdown.innerHTML).to.matchSnapshot();
130
+ (end.querySelector('.k-active')!.nextElementSibling!.nextElementSibling as HTMLElement).click();
131
+ await wait();
132
+ expect(dropdown.innerHTML).to.matchSnapshot();
133
+ dropdown.querySelector<HTMLElement>('.k-btn')!.click();
134
+ await wait();
135
+ expect(instance.get('time')).to.eql(['01:00:00', '01:59:59']);
136
+
137
+ // clear
138
+ picker.querySelector<HTMLElement>('.k-select-clear')!.click();
139
+ await wait();
140
+ expect(instance.get('time')).to.eql(null);
141
+ });
142
+
143
+ it('only select one value then click confirm button directly', async () => {
144
+ const [instance, element] = mount(RangeDemo);
145
+
146
+ const picker = element.querySelector('.k-select') as HTMLElement;
147
+ picker.click();
148
+ await wait();
149
+ const dropdown = getElement('.k-time-content')!;
150
+ const [start, end] = dropdown.querySelectorAll<HTMLElement>('.k-datepicker-calendar-wrapper');
151
+ (start.querySelector('.k-active')!.nextElementSibling as HTMLElement).click();
152
+ await wait();
153
+
154
+ // skip select end and confirm
155
+ dropdown.querySelector<HTMLElement>('.k-btn')!.click();
156
+ await wait();
157
+ expect(instance.get('time')).eql(['01:00:00', '23:59:59']);
158
+
159
+ picker.querySelector<HTMLElement>('.k-select-clear')!.click();
160
+ await wait();
161
+ picker.click();
162
+ await wait();
163
+ (end.querySelector('.k-active')!.nextElementSibling as HTMLElement).click();
164
+ dropdown.querySelector<HTMLElement>('.k-btn')!.click();
165
+ await wait();
166
+ expect(instance.get('time')).eql(['00:00:00', '00:59:59']);
167
+
168
+ // click confirm directly
169
+ picker.querySelector<HTMLElement>('.k-select-clear')!.click();
170
+ await wait();
171
+ picker.click();
172
+ await wait();
173
+ dropdown.querySelector<HTMLElement>('.k-btn')!.click();
174
+ await wait();
175
+ expect(instance.get('time')).eql(['00:00:00', '23:59:59']);
176
+ });
177
+
178
+ it('should unique', async () => {
179
+ const [instance, element] = mount(RangeDemo);
180
+ const [, multipe] = element.querySelectorAll('.k-select') as NodeListOf<HTMLElement>;
181
+
182
+ // multiple
183
+ multipe.click();
184
+ await wait();
185
+ let dropdown = getElement('.k-time-content')!;
186
+ const confirm = dropdown.querySelector('.k-btn') as HTMLElement;
187
+
188
+ confirm.click();
189
+ await wait();
190
+ expect(instance.get('timeArr')).eql([['00:00:00', '23:59:59']]);
191
+
192
+ // confirm again
193
+ confirm.click();
194
+ await wait();
195
+ expect(instance.get('timeArr')).eql([['00:00:00', '23:59:59']]);
196
+ });
197
+
198
+ it('should maintain consistency when we select the next value', async () => {
199
+ const [instance, element] = mount(RangeDemo);
200
+ const [, multipe] = element.querySelectorAll('.k-select') as NodeListOf<HTMLElement>;
201
+ instance.set('timeArr', [['01:00:00', '02:00:00']]);
202
+
203
+ // multiple
204
+ multipe.click();
205
+ await wait();
206
+ let dropdown = getElement('.k-time-content')!;
207
+ const confirm = dropdown.querySelector('.k-btn') as HTMLElement;
208
+ const [start, end] = dropdown.querySelectorAll<HTMLElement>('.k-datepicker-calendar-wrapper');
209
+ (start.querySelector('.k-active')!.nextElementSibling as HTMLElement).click();
210
+ await wait();
211
+ confirm.click();
212
+ await wait();
213
+ expect(instance.get('timeArr')).eql([
214
+ ['01:00:00', '02:00:00'],
215
+ ['02:00:00', '02:00:00'],
216
+ ]);
217
+ });
100
218
  });
101
219
 
102
220
  it('step', async () => {
@@ -123,11 +241,11 @@ describe('Timepicker', () => {
123
241
  (start.querySelector('.k-active')!.nextElementSibling as HTMLElement).click();
124
242
  await wait();
125
243
  expect(dropdown.innerHTML).to.matchSnapshot();
126
- (end.querySelector('.k-disabled')!.nextElementSibling as HTMLElement).click();
244
+ (end.querySelector('.k-active')!.previousElementSibling as HTMLElement).click();
127
245
  await wait();
128
246
  expect(dropdown.innerHTML).to.matchSnapshot();
129
247
  dropdown.querySelector<HTMLElement>('.k-btn')!.click();
130
- expect(instance.get('time')).to.eql(['00:30:00', '00:30:00']);
248
+ expect(instance.get('time')).to.eql(['00:30:00', '23:30:00']);
131
249
  });
132
250
 
133
251
  it('format', async () => {