@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
@@ -66,6 +66,7 @@ const filterInput = <Input v-if={filterable}
66
66
  container={container}
67
67
  v-model="show"
68
68
  position={position}
69
+ alwaysShowOnClick={$props.alwaysShowOnClick}
69
70
  >
70
71
  <div {...getRestProps(this)}
71
72
  class={classNameObj}
@@ -74,6 +75,7 @@ const filterInput = <Input v-if={filterable}
74
75
  ev-focusout={onFocusout}
75
76
  style={!isNullOrUndefined(width) ? addStyle(style, {width: `${width}px`}) : style}
76
77
  ref={triggerRef}
78
+ ev-click={$props.onClick}
77
79
  >
78
80
  <div class={`${k}-select-prefix`} v-if={$blocks.prefix}>
79
81
  <b:prefix />
@@ -95,7 +97,6 @@ const filterInput = <Input v-if={filterable}
95
97
  readonly={!show}
96
98
  waveDisabled={true}
97
99
  flat={flat}
98
- ev-click={$props.onClick}
99
100
  />
100
101
  <div class={`${k}-select-placeholder c-ellipsis`}
101
102
  v-else-if={!filterable && !hasValue}
@@ -31,7 +31,7 @@ import {Select, Option} from 'kpc';
31
31
  </Select>
32
32
  Days: {JSON.stringify(this.get('days'))}
33
33
  <br /><br />
34
- <Select v-model="dayWithKeywords" filterable multiple creatable keepKeywords style="margin-right: 10px">
34
+ <Select v-model="dayWithKeywords" filterable multiple creatable keepKeywords={false} style="margin-right: 10px">
35
35
  <Option value="Monday">星期一</Option>
36
36
  <Option value="Tuesday">星期二</Option>
37
37
  <Option value="Wednesday">星期三</Option>
@@ -40,7 +40,7 @@ import {Select, Option} from 'kpc';
40
40
  <Option value="Saturday">星期六</Option>
41
41
  <Option value="Sunday">星期天</Option>
42
42
  </Select>
43
- Day with keepKeywords: {JSON.stringify(this.get('dayWithKeywords'))}
43
+ Day with keepKeywords=false: {JSON.stringify(this.get('dayWithKeywords'))}
44
44
  </div>
45
45
  ```
46
46
 
@@ -31,7 +31,7 @@ sidebar: doc
31
31
  | labelMap | 建立值`value`到展示标签`label`的映射,可以在`value`不在`Option`集合中时,依然能够正确展示相应的`label` | `Map<any, string>` | `new Map()` |
32
32
  | card | 是否展示`card`模式 | `boolean` | `false` |
33
33
  | autoDisableArrow | 是否在没有更多可选项时,给箭头一个`disabled`状态来提示用户 | `boolean` | `false` |
34
- | keepKeywords | 是否在选中选项后保留搜索关键字,配合`filterable`使用 | `boolean` | `false` |
34
+ | keepKeywords | 是否在选中选项后保留搜索关键字,配合`filterable`使用 | `boolean` | `true` |
35
35
  | show | 是否展示菜单项 | `boolean` | `false` |
36
36
  | position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` &#124; `"left"` &#124; `"bottom"` &#124; `"right"` &#124; `"top"` | `{my: 'left top+8', 'left bottom'}` |
37
37
  | flat | 是否展示扁平样式 | `boolean` | `false` |
@@ -12,9 +12,9 @@ import SearchableDemo from '~/components/select/demos/searchable';
12
12
  import ImmutableDemo from '~/components/select/demos/immutable';
13
13
 
14
14
  describe('Select', () => {
15
- afterEach((done) => {
15
+ afterEach(async () => {
16
16
  unmount();
17
- setTimeout(done, 500);
17
+ await wait(500);
18
18
  });
19
19
 
20
20
  it('should select value correctly', async () => {
@@ -188,6 +188,39 @@ describe('Select', () => {
188
188
  expect(dropdown2.innerHTML).to.matchSnapshot();
189
189
  });
190
190
 
191
+ it('should select the first card of group on filtering', async () => {
192
+ const [instance, element] = mount(GroupDemo);
193
+
194
+ instance.set<string>('day', 'Saturday');
195
+ await wait();
196
+ const [, trigger] = element.querySelectorAll<HTMLElement>('.k-select');
197
+ trigger.click();
198
+ await wait();
199
+ const dropdown = getElement('.k-select-menu')!;
200
+ defaultStatusTest();
201
+
202
+ // filter
203
+ const input = trigger.querySelector('.k-input-inner') as HTMLInputElement;
204
+ input.value = 'm';
205
+ dispatchEvent(input, 'input');
206
+ await wait();
207
+ const firstTab = dropdown.querySelector('.k-tab') as HTMLElement;
208
+ expect(firstTab.classList.contains('k-active')).to.eql(true);
209
+
210
+ // clear
211
+ input.value = '';
212
+ dispatchEvent(input, 'input');
213
+ await wait();
214
+ defaultStatusTest();
215
+
216
+ function defaultStatusTest() {
217
+ const secondTab = dropdown.querySelector('.k-tab:nth-child(2)') as HTMLElement;
218
+ const item = dropdown.querySelector('.k-dropdown-item') as HTMLElement;
219
+ expect(secondTab.classList.contains('k-active')).to.eql(true);
220
+ expect(item.classList.contains('k-active')).to.eql(true);
221
+ }
222
+ });
223
+
191
224
  it('keyboard operations', async () => {
192
225
  const [instance, element] = mount(BasicDemo);
193
226
 
@@ -206,6 +239,9 @@ describe('Select', () => {
206
239
  const [instance, element] = mount(CreatableDemo);
207
240
 
208
241
  const input = element.querySelector('.k-input-inner') as HTMLInputElement;
242
+
243
+ expect(instance.get('day')).to.be.null;
244
+
209
245
  input.click();
210
246
  await wait();
211
247
  input.value = 'xxx';
@@ -213,38 +249,82 @@ describe('Select', () => {
213
249
  await wait();
214
250
  const dropdown = getElement('.k-select-menu')!;
215
251
  expect(dropdown.innerHTML).to.matchSnapshot();
216
- // select
252
+
253
+ // check the created option appears in dropdown
254
+ const createOption = dropdown.querySelector('.k-select-option');
255
+ expect(createOption).to.exist;
256
+ expect(createOption!.textContent).to.contain('xxx');
257
+
258
+ // press enter to select the custom option
217
259
  dispatchEvent(document, 'keydown', {keyCode: 13});
218
260
  await wait();
219
261
  expect(instance.get('day')).to.eql('xxx');
262
+ expect(input.value).to.eql('xxx');
220
263
 
221
- // open again
264
+ // reopen dropdown
222
265
  input.click();
223
266
  await wait();
224
267
  expect(element.innerHTML).to.matchSnapshot();
225
268
  expect(dropdown.innerHTML).to.matchSnapshot();
226
-
227
- // input again
269
+
270
+ // input another custom option
228
271
  input.value = 'yyy';
229
272
  dispatchEvent(input, 'input');
230
273
  await wait();
231
274
  expect(element.innerHTML).to.matchSnapshot();
232
275
  expect(dropdown.innerHTML).to.matchSnapshot();
233
276
 
234
- // discard
277
+ const newCreateOption = dropdown.querySelector('.k-select-option');
278
+ expect(newCreateOption).to.exist;
279
+ expect(newCreateOption!.textContent).to.contain('yyy');
280
+
281
+ // click outside to cancel selection
235
282
  dispatchEvent(document, 'click');
236
283
  await wait();
237
284
  expect(element.innerHTML).to.matchSnapshot();
238
- expect(instance.get('day')).to.eql('xxx');
285
+ expect(instance.get('day')).to.eql('xxx'); // should keep the original value
286
+ expect(input.value).to.eql('xxx'); // should restore the original value
287
+
288
+ // test multiple creatable
289
+ const [, multipleInput] = element.querySelectorAll<HTMLInputElement>('.k-input-inner');
290
+ expect(instance.get('days')).to.eql([]);
291
+
292
+ multipleInput.click();
293
+ await wait();
294
+ multipleInput.value = 'custom1';
295
+ dispatchEvent(multipleInput, 'input');
296
+ await wait();
297
+
298
+ // press enter to create and select the first custom option
299
+ dispatchEvent(document, 'keydown', {keyCode: 13});
300
+ await wait();
301
+ expect(instance.get('days')).to.include('custom1');
302
+ expect(multipleInput.value).to.eql('custom1');
303
+
304
+ // input the same option again
305
+ dispatchEvent(document, 'keydown', {keyCode: 13});
306
+ await wait();
307
+ expect(instance.get('days')).to.eql([]);
308
+ expect(multipleInput.value).to.eql('custom1');
309
+
310
+ // test select original options
311
+ multipleInput.value = 'Monday';
312
+ dispatchEvent(multipleInput, 'input');
313
+ await wait();
314
+ const multipleDropdown = getElement('.k-select-menu')!;
315
+ const mondayOption = multipleDropdown.querySelector('.k-select-option') as HTMLElement;
316
+ expect(mondayOption.textContent).to.eql('星期一');
317
+ mondayOption.click();
318
+ await wait();
319
+ expect(instance.get('days')).to.include('Monday');
239
320
  });
240
321
 
241
322
  it('keepKeywords', async () => {
242
- // 创建一个测试组件,包含keepKeywords功能
243
323
  class KeepKeywordsDemo extends Component<{days: string[]}> {
244
324
  static template = `
245
325
  const {Select, Option} = this;
246
326
  <div>
247
- <Select v-model="days" filterable multiple creatable keepKeywords>
327
+ <Select v-model="days" filterable multiple creatable keepKeywords={false}>
248
328
  <Option value="Monday">星期一</Option>
249
329
  <Option value="Tuesday">星期二</Option>
250
330
  <Option value="Wednesday">星期三</Option>
@@ -263,50 +343,50 @@ describe('Select', () => {
263
343
  const [instance, element] = mount(KeepKeywordsDemo);
264
344
  const input = element.querySelector('.k-input-inner') as HTMLInputElement;
265
345
 
266
- // 1. 输入自定义选项 "custom1"
346
+ // input custom option "custom1"
267
347
  input.click();
268
348
  await wait();
269
349
  input.value = 'custom1';
270
350
  dispatchEvent(input, 'input');
271
351
  await wait();
272
352
 
273
- // 验证创建的选项出现在dropdown
353
+ // check the created option appears in dropdown
274
354
  const dropdown = getElement('.k-select-menu')!;
275
355
  expect(dropdown.innerHTML).to.contain('custom1');
276
356
 
277
- // 2. 按回车创建并选中
357
+ // press enter to create and select
278
358
  dispatchEvent(document, 'keydown', {keyCode: 13});
279
359
  await wait();
280
360
 
281
- // 验证选项被选中,且输入框被清空
361
+ // check the option is selected, and the input is cleared
282
362
  expect(instance.get('days')).to.eql(['custom1']);
283
- expect(input.value).to.eql(''); // keepKeywords=true时应该清空输入框
363
+ expect(input.value).to.eql('');
284
364
 
285
- // 3. 再次输入相同的选项 "custom1"
365
+ // input the same option "custom1" again
286
366
  input.value = 'custom1';
287
367
  dispatchEvent(input, 'input');
288
368
  await wait();
289
369
 
290
- // 4. 再次按回车
370
+ // press enter again
291
371
  dispatchEvent(document, 'keydown', {keyCode: 13});
292
372
  await wait();
293
373
 
294
- // 验证选项仍然被选中(不会被取消选中),且输入框被清空
295
- expect(instance.get('days')).to.eql(['custom1']); // 应该保持选中状态
296
- expect(input.value).to.eql(''); // 输入框应该被清空
374
+ // check the option is still selected (not be unselected), and the input is cleared
375
+ expect(instance.get('days')).to.eql(['custom1']); // should be selected
376
+ expect(input.value).to.eql(''); // should be cleared
297
377
 
298
- // 5. 输入另一个自定义选项 "custom2"
378
+ // input another custom option "custom2"
299
379
  input.value = 'custom2';
300
380
  dispatchEvent(input, 'input');
301
381
  await wait();
302
382
  dispatchEvent(document, 'keydown', {keyCode: 13});
303
383
  await wait();
304
384
 
305
- // 验证两个选项都被选中
385
+ // check two options are selected
306
386
  expect(instance.get('days')).to.eql(['custom1', 'custom2']);
307
387
  expect(input.value).to.eql('');
308
388
 
309
- // 6. 测试原有选项的正常行为
389
+ // test the normal behavior of original options
310
390
  input.click();
311
391
  await wait();
312
392
  const mondayOption = dropdown.querySelector('[data-value="Monday"]') as HTMLElement;
@@ -315,7 +395,7 @@ describe('Select', () => {
315
395
  await wait();
316
396
  expect(instance.get('days')).to.include('Monday');
317
397
 
318
- // 再次点击应该能取消选中(原有选项不受keepKeywords影响)
398
+ // click again should be unselected (original options are not affected by keepKeywords)
319
399
  mondayOption.click();
320
400
  await wait();
321
401
  expect(instance.get('days')).to.not.include('Monday');
@@ -383,21 +463,47 @@ describe('Select', () => {
383
463
  });
384
464
 
385
465
  it('Searchable with multiple should show correct initial checkbox state', async () => {
386
- const [instance, element] = mount(SearchableDemo);
466
+ class Demo extends Component {
467
+ static template = `
468
+ const {Select, Option} = this;
469
+ <Select v-model="days" searchable multiple>
470
+ <Option value="Monday" disabled>星期一</Option>
471
+ <Option value="Tuesday">星期二</Option>
472
+ <Option value="Wednesday">星期三</Option>
473
+ <Option value="Thursday">星期四</Option>
474
+ <Option value="Friday">星期五</Option>
475
+ <Option value="Saturday">星期六</Option>
476
+ <Option value="Sunday">星期天</Option>
477
+ <b:values args="[value]">
478
+ <div class="k-value">
479
+ 已选择{value.length}项 / 共7项
480
+ </div>
481
+ </b:values>
482
+ </Select>
483
+ `;
484
+ static defaults() {
485
+ return {
486
+ days: ['Tuesday']
487
+ }
488
+ }
489
+ private Tooltip = Tooltip;
490
+ private Select = Select;
491
+ private Option = Option;
492
+ }
493
+
494
+ const [instance, element] = mount(Demo as any);
387
495
 
388
- // 验证初始值
389
496
  expect(instance.get('days')).to.eql(['Tuesday']);
390
497
 
391
- // 第一次打开dropdown,检查初始状态
392
- const [, select] = element.querySelectorAll<HTMLElement>('.k-select');
393
- select.click();
498
+ // first open dropdown, check initial state
499
+ element.click();
394
500
  await wait();
395
501
 
396
502
  const dropdown = getElement('.k-select-menu')!;
397
503
  const checkboxes = dropdown.querySelectorAll<HTMLInputElement>('.k-checkbox input[type="checkbox"]');
398
504
  const options = dropdown.querySelectorAll<HTMLElement>('.k-select-option');
399
505
 
400
- // 找到Tuesday选项对应的checkbox
506
+ // find the checkbox of Tuesday option
401
507
  let tuesdayCheckbox: HTMLInputElement | null = null;
402
508
  let tuesdayOption: HTMLElement | null = null;
403
509
 
@@ -408,21 +514,21 @@ describe('Select', () => {
408
514
  }
409
515
  });
410
516
 
411
- // 验证Tuesday的checkbox应该被选中
517
+ // check the checkbox of Tuesday should be checked
412
518
  expect(tuesdayCheckbox).to.exist;
413
519
  expect(tuesdayCheckbox!.checked).to.be.true;
414
520
 
415
- // 验证Tuesday选项应该有active样式
521
+ // check the Tuesday option should have active style
416
522
  expect(tuesdayOption).to.exist;
417
523
  expect(tuesdayOption!.className).to.include('k-active');
418
524
 
419
- // 关闭dropdown
525
+ // close dropdown
420
526
  const [cancel] = dropdown.querySelectorAll<HTMLElement>('.k-select-footer .k-btn');
421
527
  cancel.click();
422
528
  await wait();
423
529
 
424
- // 再次打开dropdown,验证状态仍然正确
425
- select.click();
530
+ // reopen dropdown, check the state is still correct
531
+ element.click();
426
532
  await wait();
427
533
 
428
534
  const dropdown2 = getElement('.k-select-menu')!;
@@ -439,7 +545,7 @@ describe('Select', () => {
439
545
  }
440
546
  });
441
547
 
442
- // 验证第二次打开时状态依然正确
548
+ // check the state is still correct when reopen
443
549
  expect(tuesdayCheckbox2!.checked).to.be.true;
444
550
  expect(tuesdayOption2!.className).to.include('k-active');
445
551
  });
@@ -12,7 +12,7 @@ export class SelectMenu extends Component<{values: any[]}> {
12
12
  static template = template;
13
13
 
14
14
  public select: Select<any, boolean> = inject(SELECT)!;
15
- private card = useCard(this.select.label.activeIndices);
15
+ private card = useCard(this.select.label.activeIndices, this.select.input.keywords);
16
16
  private searchable = useSearchable();
17
17
  private config = useConfigContext();
18
18
  }
@@ -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;
@@ -2,13 +2,31 @@ import {Component, TypeDefs, useInstance, Children, Blocks, createRef, NonNullab
2
2
  import {eachChildren, isComponentVNode, last} from '../utils';
3
3
  import {EMPTY_OBJ} from 'intact-shared';
4
4
  import {OptionGroup} from './group';
5
- import {useState} from '../../hooks/useState';
5
+ import {useState, State, watchState} from '../../hooks/useState';
6
+ import type { SelectMenu } from './menu';
6
7
 
7
- export function useCard(defaultActiveIndex: NonNullableRefObject<number[]>) {
8
- const children = useInstance()!.get('children');
8
+ export function useCard(
9
+ defaultActiveIndex: NonNullableRefObject<number[]>,
10
+ keywords: State<string>
11
+ ) {
12
+ const instance = useInstance() as SelectMenu;
9
13
  const activeIndex = useState<number>(last(defaultActiveIndex.value) || 0);
10
14
 
11
- function process(children: Children) {
15
+ watchState(keywords, (keywords) => {
16
+ if (keywords) {
17
+ activeIndex.set(0);
18
+ } else {
19
+ setDefaultActiveIndex();
20
+ }
21
+ });
22
+
23
+ instance.select.on('show', setDefaultActiveIndex);
24
+
25
+ function setDefaultActiveIndex() {
26
+ activeIndex.set(last(defaultActiveIndex.value) || 0);
27
+ }
28
+
29
+ function process(children: Children, isSearching: boolean) {
12
30
  const groupLabels: Children[] | Blocks[string][] = [];
13
31
  const _children: Children[] = [];
14
32
  let index = 0;
@@ -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
  });
@@ -227,6 +227,24 @@ describe('Spinner', () => {
227
227
  expect(instance.get('value1')).to.eql(8.4);
228
228
  });
229
229
 
230
+ it('forceStep without min value', async () => {
231
+ class Demo extends Component {
232
+ static template = `const {Spinner} = this;
233
+ <Spinner step={1} v-model="value" forceStep />
234
+ `;
235
+ static defaults() {
236
+ return {value: 1};
237
+ }
238
+ private Spinner = Spinner;
239
+ }
240
+ const [instance, element] = mount(Demo);
241
+ expect(instance.get('value')).to.eql(1);
242
+
243
+ instance.set<number>('value', -1);
244
+ await wait();
245
+ expect(instance.get('value')).to.eql(-1);
246
+ });
247
+
230
248
  it('dynamic step', async () => {
231
249
  const [instance, element] = mount(DynamicStepDemo);
232
250
 
@@ -78,7 +78,8 @@ export function minMaxStep(value: number, min: number, max: number, step: number
78
78
  if (value >= max) return max;
79
79
  if (value <= min) return min;
80
80
  if (step) {
81
- value = Number((Math.round((value - min) / step) * step + min).toFixed(10))
81
+ let _min = min === -Infinity ? 0 : min;
82
+ value = Number((Math.round((value - _min) / step) * step + _min).toFixed(10))
82
83
  // value = Number((Math.round(value / step) * step).toFixed(10))
83
84
  return minMaxStep(value, min, max, null);
84
85
  }
@@ -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;