@king-design/intact 3.5.1 → 3.6.0-beta.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 (227) hide show
  1. package/components/breadcrumb/demos/separator.md +4 -4
  2. package/components/breadcrumb/index.vdt +1 -1
  3. package/components/breadcrumb/styles.ts +3 -2
  4. package/components/button/index.md +1 -0
  5. package/components/datepicker/basepicker.ts +60 -13
  6. package/components/datepicker/calendar.ts +5 -1
  7. package/components/datepicker/calendar.vdt +20 -6
  8. package/components/datepicker/dayjs.ts +22 -2
  9. package/components/datepicker/demos/multiple.md +0 -5
  10. package/components/datepicker/demos/nowrap.md +35 -0
  11. package/components/datepicker/demos/yearMonth.md +8 -2
  12. package/components/datepicker/helpers.ts +5 -5
  13. package/components/datepicker/index.md +3 -2
  14. package/components/datepicker/index.spec.ts +107 -90
  15. package/components/datepicker/index.ts +23 -5
  16. package/components/datepicker/index.vdt +34 -35
  17. package/components/datepicker/styles.ts +102 -3
  18. package/components/datepicker/useDisabled.ts +3 -3
  19. package/components/datepicker/useFormats.ts +2 -0
  20. package/components/datepicker/useMergeRange.ts +54 -0
  21. package/components/datepicker/usePosition.ts +169 -0
  22. package/components/datepicker/useQuarters.ts +47 -0
  23. package/components/datepicker/useShowDate.ts +42 -11
  24. package/components/datepicker/useValue.ts +35 -4
  25. package/components/datepicker/useWeeks.ts +58 -0
  26. package/components/dialog/useFixBody.ts +7 -64
  27. package/components/ellipsis/styles.ts +4 -0
  28. package/components/form/styles.ts +1 -0
  29. package/components/scrollSelect/index.spec.ts +3 -3
  30. package/components/scrollSelect/useMouseEvents.ts +23 -10
  31. package/components/select/base.vdt +2 -1
  32. package/components/select/demos/creatable.md +13 -0
  33. package/components/select/index.md +1 -0
  34. package/components/select/index.spec.ts +180 -0
  35. package/components/select/option.ts +9 -1
  36. package/components/select/select.ts +2 -0
  37. package/components/select/useFilterable.ts +1 -1
  38. package/components/select/useInput.ts +4 -2
  39. package/components/select/useSearchable.ts +2 -2
  40. package/components/table/table.vdt +3 -3
  41. package/components/timepicker/demos/step.md +1 -1
  42. package/components/timepicker/panelPicker.vdt +5 -1
  43. package/components/timepicker/styles.ts +0 -1
  44. package/components/tour/demos/basic.md +73 -0
  45. package/components/tour/demos/beforeChange.md +109 -0
  46. package/components/tour/demos/closable.md +70 -0
  47. package/components/tour/demos/custom.md +98 -0
  48. package/components/tour/demos/customText.md +94 -0
  49. package/components/tour/demos/declarative.md +72 -0
  50. package/components/tour/demos/events.md +101 -0
  51. package/components/tour/demos/maskClosable.md +76 -0
  52. package/components/tour/demos/notarget.md +59 -0
  53. package/components/tour/index.md +48 -0
  54. package/components/tour/index.spec.ts +259 -0
  55. package/components/tour/index.ts +2 -0
  56. package/components/tour/step.ts +55 -0
  57. package/components/tour/step.vdt +75 -0
  58. package/components/tour/styles.ts +283 -0
  59. package/components/tour/tour.ts +107 -0
  60. package/components/tour/tour.vdt +83 -0
  61. package/components/tour/useArrow.ts +46 -0
  62. package/components/tour/useFixBody.ts +22 -0
  63. package/components/tour/useHighlight.ts +36 -0
  64. package/components/tour/useMaskClosable.ts +26 -0
  65. package/components/tour/useNavigation.ts +46 -0
  66. package/components/tour/usePosition.ts +91 -0
  67. package/components/tour/useSteps.ts +80 -0
  68. package/components/tree/useChecked.ts +6 -4
  69. package/components/treeSelect/index.spec.ts +13 -1
  70. package/components/virtualList/useVirtualRows.ts +1 -1
  71. package/es/components/breadcrumb/index.vdt.js +2 -1
  72. package/es/components/breadcrumb/styles.js +5 -3
  73. package/es/components/datepicker/basepicker.d.ts +4 -2
  74. package/es/components/datepicker/basepicker.js +46 -13
  75. package/es/components/datepicker/calendar.d.ts +34 -6
  76. package/es/components/datepicker/calendar.js +4 -0
  77. package/es/components/datepicker/calendar.vdt.js +21 -5
  78. package/es/components/datepicker/dayjs.d.ts +13 -2
  79. package/es/components/datepicker/dayjs.js +6 -0
  80. package/es/components/datepicker/helpers.d.ts +5 -5
  81. package/es/components/datepicker/index.d.ts +17 -2
  82. package/es/components/datepicker/index.js +23 -5
  83. package/es/components/datepicker/index.spec.js +356 -355
  84. package/es/components/datepicker/index.vdt.js +25 -29
  85. package/es/components/datepicker/styles.d.ts +17 -0
  86. package/es/components/datepicker/styles.js +29 -2
  87. package/es/components/datepicker/useDisabled.d.ts +2 -2
  88. package/es/components/datepicker/useDisabled.js +1 -1
  89. package/es/components/datepicker/useFormats.js +3 -1
  90. package/es/components/datepicker/useMergeRange.d.ts +5 -0
  91. package/es/components/datepicker/useMergeRange.js +50 -0
  92. package/es/components/datepicker/usePosition.d.ts +10 -0
  93. package/es/components/datepicker/usePosition.js +166 -0
  94. package/es/components/datepicker/useQuarters.d.ts +15 -0
  95. package/es/components/datepicker/useQuarters.js +36 -0
  96. package/es/components/datepicker/useShowDate.d.ts +1 -1
  97. package/es/components/datepicker/useShowDate.js +42 -9
  98. package/es/components/datepicker/useStatus.d.ts +1 -1
  99. package/es/components/datepicker/useValue.d.ts +1 -0
  100. package/es/components/datepicker/useValue.js +26 -2
  101. package/es/components/datepicker/useWeeks.d.ts +19 -0
  102. package/es/components/datepicker/useWeeks.js +48 -0
  103. package/es/components/dialog/useFixBody.js +6 -58
  104. package/es/components/ellipsis/styles.js +1 -1
  105. package/es/components/form/styles.js +1 -1
  106. package/es/components/scrollSelect/index.spec.js +4 -6
  107. package/es/components/scrollSelect/useMouseEvents.js +21 -9
  108. package/es/components/select/base.vdt.js +4 -2
  109. package/es/components/select/index.spec.js +269 -42
  110. package/es/components/select/option.d.ts +1 -0
  111. package/es/components/select/option.js +9 -2
  112. package/es/components/select/select.d.ts +1 -0
  113. package/es/components/select/select.js +2 -1
  114. package/es/components/select/useFilterable.js +2 -1
  115. package/es/components/select/useInput.js +5 -2
  116. package/es/components/select/useSearchable.js +1 -0
  117. package/es/components/table/table.vdt.js +4 -2
  118. package/es/components/timepicker/panelPicker.d.ts +2 -1
  119. package/es/components/timepicker/panelPicker.vdt.js +12 -4
  120. package/es/components/timepicker/selectPicker.d.ts +1 -1
  121. package/es/components/timepicker/styles.js +1 -1
  122. package/es/components/timepicker/useDisabled.d.ts +1 -1
  123. package/es/components/timepicker/useValue.d.ts +1 -0
  124. package/es/components/tour/index.d.ts +2 -0
  125. package/es/components/tour/index.js +2 -0
  126. package/es/components/tour/index.spec.d.ts +1 -0
  127. package/es/components/tour/index.spec.js +356 -0
  128. package/es/components/tour/step.d.ts +23 -0
  129. package/es/components/tour/step.js +46 -0
  130. package/es/components/tour/step.vdt.js +74 -0
  131. package/es/components/tour/styles.d.ts +7 -0
  132. package/es/components/tour/styles.js +84 -0
  133. package/es/components/tour/tour.d.ts +73 -0
  134. package/es/components/tour/tour.js +70 -0
  135. package/es/components/tour/tour.vdt.js +66 -0
  136. package/es/components/tour/useArrow.d.ts +4 -0
  137. package/es/components/tour/useArrow.js +40 -0
  138. package/es/components/tour/useFixBody.d.ts +4 -0
  139. package/es/components/tour/useFixBody.js +17 -0
  140. package/es/components/tour/useHighlight.d.ts +4 -0
  141. package/es/components/tour/useHighlight.js +31 -0
  142. package/es/components/tour/useMaskClosable.d.ts +1 -0
  143. package/es/components/tour/useMaskClosable.js +25 -0
  144. package/es/components/tour/useNavigation.d.ts +5 -0
  145. package/es/components/tour/useNavigation.js +103 -0
  146. package/es/components/tour/usePosition.d.ts +6 -0
  147. package/es/components/tour/usePosition.js +93 -0
  148. package/es/components/tour/useSteps.d.ts +6 -0
  149. package/es/components/tour/useSteps.js +68 -0
  150. package/es/components/tree/useChecked.js +6 -4
  151. package/es/components/treeSelect/index.spec.js +20 -5
  152. package/es/components/virtualList/useVirtualRows.js +1 -1
  153. package/es/hooks/useDocumentClick.js +3 -3
  154. package/es/hooks/useFixBody.d.ts +11 -0
  155. package/es/hooks/useFixBody.js +72 -0
  156. package/es/index.d.ts +3 -2
  157. package/es/index.js +3 -2
  158. package/es/site/data/components/breadcrumb/demos/separator/react.js +7 -5
  159. package/es/site/data/components/datepicker/demos/multiple/index.d.ts +0 -1
  160. package/es/site/data/components/datepicker/demos/multiple/index.js +1 -2
  161. package/es/site/data/components/datepicker/demos/multiple/react.d.ts +0 -1
  162. package/es/site/data/components/datepicker/demos/multiple/react.js +2 -13
  163. package/es/site/data/components/datepicker/demos/nowrap/index.d.ts +10 -0
  164. package/es/site/data/components/datepicker/demos/nowrap/index.js +19 -0
  165. package/es/site/data/components/datepicker/demos/nowrap/react.d.ts +10 -0
  166. package/es/site/data/components/datepicker/demos/nowrap/react.js +49 -0
  167. package/es/site/data/components/datepicker/demos/yearMonth/index.d.ts +2 -0
  168. package/es/site/data/components/datepicker/demos/yearMonth/index.js +3 -1
  169. package/es/site/data/components/datepicker/demos/yearMonth/react.d.ts +2 -0
  170. package/es/site/data/components/datepicker/demos/yearMonth/react.js +21 -1
  171. package/es/site/data/components/select/demos/creatable/index.d.ts +1 -0
  172. package/es/site/data/components/select/demos/creatable/index.js +2 -1
  173. package/es/site/data/components/select/demos/creatable/react.d.ts +1 -0
  174. package/es/site/data/components/select/demos/creatable/react.js +31 -2
  175. package/es/site/data/components/select/demos/searchable/index.js +1 -1
  176. package/es/site/data/components/select/demos/searchable/react.js +1 -1
  177. package/es/site/data/components/tour/demos/basic/index.d.ts +17 -0
  178. package/es/site/data/components/tour/demos/basic/index.js +46 -0
  179. package/es/site/data/components/tour/demos/basic/react.d.ts +16 -0
  180. package/es/site/data/components/tour/demos/basic/react.js +82 -0
  181. package/es/site/data/components/tour/demos/beforeChange/index.d.ts +20 -0
  182. package/es/site/data/components/tour/demos/beforeChange/index.js +69 -0
  183. package/es/site/data/components/tour/demos/beforeChange/react.d.ts +19 -0
  184. package/es/site/data/components/tour/demos/beforeChange/react.js +129 -0
  185. package/es/site/data/components/tour/demos/closable/index.d.ts +18 -0
  186. package/es/site/data/components/tour/demos/closable/index.js +42 -0
  187. package/es/site/data/components/tour/demos/closable/react.d.ts +17 -0
  188. package/es/site/data/components/tour/demos/closable/react.js +85 -0
  189. package/es/site/data/components/tour/demos/custom/index.d.ts +11 -0
  190. package/es/site/data/components/tour/demos/custom/index.js +35 -0
  191. package/es/site/data/components/tour/demos/custom/react.d.ts +11 -0
  192. package/es/site/data/components/tour/demos/custom/react.js +108 -0
  193. package/es/site/data/components/tour/demos/customButtons/index.d.ts +33 -0
  194. package/es/site/data/components/tour/demos/customButtons/index.js +55 -0
  195. package/es/site/data/components/tour/demos/customButtons/react.d.ts +33 -0
  196. package/es/site/data/components/tour/demos/customButtons/react.js +99 -0
  197. package/es/site/data/components/tour/demos/customText/index.d.ts +20 -0
  198. package/es/site/data/components/tour/demos/customText/index.js +54 -0
  199. package/es/site/data/components/tour/demos/customText/react.d.ts +19 -0
  200. package/es/site/data/components/tour/demos/customText/react.js +95 -0
  201. package/es/site/data/components/tour/demos/declarative/index.d.ts +11 -0
  202. package/es/site/data/components/tour/demos/declarative/index.js +36 -0
  203. package/es/site/data/components/tour/demos/declarative/react.d.ts +10 -0
  204. package/es/site/data/components/tour/demos/declarative/react.js +80 -0
  205. package/es/site/data/components/tour/demos/events/index.d.ts +18 -0
  206. package/es/site/data/components/tour/demos/events/index.js +58 -0
  207. package/es/site/data/components/tour/demos/events/react.d.ts +18 -0
  208. package/es/site/data/components/tour/demos/events/react.js +101 -0
  209. package/es/site/data/components/tour/demos/maskClosable/index.d.ts +18 -0
  210. package/es/site/data/components/tour/demos/maskClosable/index.js +47 -0
  211. package/es/site/data/components/tour/demos/maskClosable/react.d.ts +17 -0
  212. package/es/site/data/components/tour/demos/maskClosable/react.js +95 -0
  213. package/es/site/data/components/tour/demos/notarget/index.d.ts +11 -0
  214. package/es/site/data/components/tour/demos/notarget/index.js +35 -0
  215. package/es/site/data/components/tour/demos/notarget/react.d.ts +10 -0
  216. package/es/site/data/components/tour/demos/notarget/react.js +61 -0
  217. package/es/site/data/components/tour/index.d.ts +57 -0
  218. package/es/site/data/components/tour/index.js +32 -0
  219. package/es/site/src/pages/resource/index.js +1 -1
  220. package/es/styles/fonts/iconfont.js +2 -1
  221. package/es/styles/global.js +2 -1
  222. package/hooks/useDocumentClick.ts +3 -3
  223. package/hooks/useFixBody.ts +87 -0
  224. package/index.ts +3 -2
  225. package/package.json +1 -1
  226. package/styles/fonts/iconfont.ts +2 -1
  227. package/styles/global.ts +2 -1
@@ -28,12 +28,12 @@ export function useMouseEvents(
28
28
  },
29
29
 
30
30
  onMove(e: MouseEvent) {
31
- const deltaY = e.clientY - y;
31
+ const deltaY = (e.clientY - y) * 0.8;
32
32
  dragged = !!deltaY;
33
33
  y = e.clientY;
34
34
 
35
35
  const _deltaY = y - initY;
36
- let offsetIndex = Math.floor(Math.abs(_deltaY) / itemHeight);
36
+ let offsetIndex = Math.floor(Math.abs(_deltaY) / itemHeight * 1.2);
37
37
  if (offsetIndex) {
38
38
  if (_deltaY < 0) {
39
39
  offsetIndex = -offsetIndex;
@@ -63,25 +63,38 @@ export function useMouseEvents(
63
63
 
64
64
  function onWheel(e: WheelEvent) {
65
65
  e.preventDefault();
66
- itemHeight = getItemHeight();
67
- if (e.deltaY > 0) {
68
- // down
69
- setByRelativeIndex(1, null, true);
70
- } else {
71
- setByRelativeIndex(-1, null, true);
66
+
67
+ itemHeight = getItemHeight();
68
+
69
+ const threshold = itemHeight * 0.6;
70
+ deltaY = (deltaY || 0) + e.deltaY;
71
+
72
+ if (Math.abs(deltaY) >= threshold) {
73
+ if (deltaY > 0) {
74
+ setByRelativeIndex(1, null, true);
75
+ } else {
76
+ setByRelativeIndex(-1, null, true);
77
+ }
78
+ deltaY = 0;
72
79
  }
73
80
  }
74
81
 
75
82
  // throttle onWheel
76
- const _onWheel = throttle(onWheel, 0, e => e.preventDefault());
83
+ const _onWheel = throttle(onWheel, 50, e => e.preventDefault());
77
84
 
78
85
  function onClick(item: any, index: number) {
79
- // if _dragged, do not trigger click event, #123
86
+ // if dragged, do not trigger click event
80
87
  if (dragged) return;
81
88
 
82
89
  const {count} = instance.get();
83
90
  const half = Math.floor(count! / 2);
84
91
  const itemHeight = getItemHeight();
92
+
93
+ const currentIndex = list.data.value.findIndex(v => v.value === list.value.value);
94
+ const targetOffset = index - half;
95
+ if (currentIndex + targetOffset < 0 || currentIndex + targetOffset >= list.data.value.length) {
96
+ return;
97
+ }
85
98
 
86
99
  translate.set(translate.value - itemHeight * (index - half));
87
100
  marginTop.set(marginTop.value + itemHeight * (index - half));
@@ -17,7 +17,7 @@ const {
17
17
  className, container,
18
18
  inline, style, width, show,
19
19
  position, flat, nowrap,
20
- draggable,
20
+ draggable, range,
21
21
  } = this.get();
22
22
  const { k } = this.config;
23
23
 
@@ -95,6 +95,7 @@ const filterInput = <Input v-if={filterable}
95
95
  readonly={!show}
96
96
  waveDisabled={true}
97
97
  flat={flat}
98
+ ev-click={$props.onClick}
98
99
  />
99
100
  <div class={`${k}-select-placeholder c-ellipsis`}
100
101
  v-else-if={!filterable && !hasValue}
@@ -30,6 +30,17 @@ import {Select, Option} from 'kpc';
30
30
  <Option value="Sunday">星期天</Option>
31
31
  </Select>
32
32
  Days: {JSON.stringify(this.get('days'))}
33
+ <br /><br />
34
+ <Select v-model="dayWithKeywords" filterable multiple creatable keepKeywords style="margin-right: 10px">
35
+ <Option value="Monday">星期一</Option>
36
+ <Option value="Tuesday">星期二</Option>
37
+ <Option value="Wednesday">星期三</Option>
38
+ <Option value="Thursday">星期四</Option>
39
+ <Option value="Friday">星期五</Option>
40
+ <Option value="Saturday">星期六</Option>
41
+ <Option value="Sunday">星期天</Option>
42
+ </Select>
43
+ Day with keepKeywords: {JSON.stringify(this.get('dayWithKeywords'))}
33
44
  </div>
34
45
  ```
35
46
 
@@ -37,6 +48,7 @@ import {Select, Option} from 'kpc';
37
48
  interface Props {
38
49
  day?: string | null
39
50
  days?: string[]
51
+ dayWithKeywords?: string[]
40
52
  }
41
53
 
42
54
  export default class extends Component<Props> {
@@ -45,6 +57,7 @@ export default class extends Component<Props> {
45
57
  return {
46
58
  day: null,
47
59
  days: [],
60
+ dayWithKeywords: [],
48
61
  } as Props;
49
62
  }
50
63
  }
@@ -31,6 +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
35
  | show | 是否展示菜单项 | `boolean` | `false` |
35
36
  | position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` &#124; `"left"` &#124; `"bottom"` &#124; `"right"` &#124; `"top"` | `{my: 'left top+8', 'left bottom'}` |
36
37
  | flat | 是否展示扁平样式 | `boolean` | `false` |
@@ -238,6 +238,90 @@ describe('Select', () => {
238
238
  expect(instance.get('day')).to.eql('xxx');
239
239
  });
240
240
 
241
+ it('keepKeywords', async () => {
242
+ // 创建一个测试组件,包含keepKeywords功能
243
+ class KeepKeywordsDemo extends Component<{days: string[]}> {
244
+ static template = `
245
+ const {Select, Option} = this;
246
+ <div>
247
+ <Select v-model="days" filterable multiple creatable keepKeywords>
248
+ <Option value="Monday">星期一</Option>
249
+ <Option value="Tuesday">星期二</Option>
250
+ <Option value="Wednesday">星期三</Option>
251
+ </Select>
252
+ </div>
253
+ `;
254
+ static defaults() {
255
+ return {
256
+ days: [] as string[],
257
+ };
258
+ }
259
+ private Select = Select as any;
260
+ private Option = Option as any;
261
+ }
262
+
263
+ const [instance, element] = mount(KeepKeywordsDemo);
264
+ const input = element.querySelector('.k-input-inner') as HTMLInputElement;
265
+
266
+ // 1. 输入自定义选项 "custom1"
267
+ input.click();
268
+ await wait();
269
+ input.value = 'custom1';
270
+ dispatchEvent(input, 'input');
271
+ await wait();
272
+
273
+ // 验证创建的选项出现在dropdown中
274
+ const dropdown = getElement('.k-select-menu')!;
275
+ expect(dropdown.innerHTML).to.contain('custom1');
276
+
277
+ // 2. 按回车创建并选中
278
+ dispatchEvent(document, 'keydown', {keyCode: 13});
279
+ await wait();
280
+
281
+ // 验证选项被选中,且输入框被清空
282
+ expect(instance.get('days')).to.eql(['custom1']);
283
+ expect(input.value).to.eql(''); // keepKeywords=true时应该清空输入框
284
+
285
+ // 3. 再次输入相同的选项 "custom1"
286
+ input.value = 'custom1';
287
+ dispatchEvent(input, 'input');
288
+ await wait();
289
+
290
+ // 4. 再次按回车
291
+ dispatchEvent(document, 'keydown', {keyCode: 13});
292
+ await wait();
293
+
294
+ // 验证选项仍然被选中(不会被取消选中),且输入框被清空
295
+ expect(instance.get('days')).to.eql(['custom1']); // 应该保持选中状态
296
+ expect(input.value).to.eql(''); // 输入框应该被清空
297
+
298
+ // 5. 输入另一个自定义选项 "custom2"
299
+ input.value = 'custom2';
300
+ dispatchEvent(input, 'input');
301
+ await wait();
302
+ dispatchEvent(document, 'keydown', {keyCode: 13});
303
+ await wait();
304
+
305
+ // 验证两个选项都被选中
306
+ expect(instance.get('days')).to.eql(['custom1', 'custom2']);
307
+ expect(input.value).to.eql('');
308
+
309
+ // 6. 测试原有选项的正常行为
310
+ input.click();
311
+ await wait();
312
+ const mondayOption = dropdown.querySelector('[data-value="Monday"]') as HTMLElement;
313
+ if (mondayOption) {
314
+ mondayOption.click();
315
+ await wait();
316
+ expect(instance.get('days')).to.include('Monday');
317
+
318
+ // 再次点击应该能取消选中(原有选项不受keepKeywords影响)
319
+ mondayOption.click();
320
+ await wait();
321
+ expect(instance.get('days')).to.not.include('Monday');
322
+ }
323
+ });
324
+
241
325
  it('Tooltip with Select', async () => {
242
326
  class Demo extends Component {
243
327
  static template = `
@@ -298,6 +382,68 @@ describe('Select', () => {
298
382
  expect(instance.get('days')).include('Monday')
299
383
  });
300
384
 
385
+ it('Searchable with multiple should show correct initial checkbox state', async () => {
386
+ const [instance, element] = mount(SearchableDemo);
387
+
388
+ // 验证初始值
389
+ expect(instance.get('days')).to.eql(['Tuesday']);
390
+
391
+ // 第一次打开dropdown,检查初始状态
392
+ const [, select] = element.querySelectorAll<HTMLElement>('.k-select');
393
+ select.click();
394
+ await wait();
395
+
396
+ const dropdown = getElement('.k-select-menu')!;
397
+ const checkboxes = dropdown.querySelectorAll<HTMLInputElement>('.k-checkbox input[type="checkbox"]');
398
+ const options = dropdown.querySelectorAll<HTMLElement>('.k-select-option');
399
+
400
+ // 找到Tuesday选项对应的checkbox
401
+ let tuesdayCheckbox: HTMLInputElement | null = null;
402
+ let tuesdayOption: HTMLElement | null = null;
403
+
404
+ options.forEach((option, index) => {
405
+ if (option.textContent?.includes('星期二')) {
406
+ tuesdayCheckbox = checkboxes[index];
407
+ tuesdayOption = option;
408
+ }
409
+ });
410
+
411
+ // 验证Tuesday的checkbox应该被选中
412
+ expect(tuesdayCheckbox).to.exist;
413
+ expect(tuesdayCheckbox!.checked).to.be.true;
414
+
415
+ // 验证Tuesday选项应该有active样式
416
+ expect(tuesdayOption).to.exist;
417
+ expect(tuesdayOption!.className).to.include('k-active');
418
+
419
+ // 关闭dropdown
420
+ const [cancel] = dropdown.querySelectorAll<HTMLElement>('.k-select-footer .k-btn');
421
+ cancel.click();
422
+ await wait();
423
+
424
+ // 再次打开dropdown,验证状态仍然正确
425
+ select.click();
426
+ await wait();
427
+
428
+ const dropdown2 = getElement('.k-select-menu')!;
429
+ const checkboxes2 = dropdown2.querySelectorAll<HTMLInputElement>('.k-checkbox input[type="checkbox"]');
430
+ const options2 = dropdown2.querySelectorAll<HTMLElement>('.k-select-option');
431
+
432
+ let tuesdayCheckbox2: HTMLInputElement | null = null;
433
+ let tuesdayOption2: HTMLElement | null = null;
434
+
435
+ options2.forEach((option, index) => {
436
+ if (option.textContent?.includes('星期二')) {
437
+ tuesdayCheckbox2 = checkboxes2[index];
438
+ tuesdayOption2 = option;
439
+ }
440
+ });
441
+
442
+ // 验证第二次打开时状态依然正确
443
+ expect(tuesdayCheckbox2!.checked).to.be.true;
444
+ expect(tuesdayOption2!.className).to.include('k-active');
445
+ });
446
+
301
447
  it('disabled option does not allow clearable and close', async () => {
302
448
  const [instance, element] = mount(ImmutableDemo);
303
449
 
@@ -328,6 +474,40 @@ describe('Select', () => {
328
474
  // expect(clear).to.be.null;
329
475
  });
330
476
 
477
+ it('should handle async data correctly', async () => {
478
+ class Demo extends Component<{list: number[]}> {
479
+ static template = `
480
+ const {Select, Option} = this;
481
+ <Select v-model="day" virtual>
482
+ <Option v-for={this.get('list')} value={$value}>
483
+ {$value}
484
+ </Option>
485
+ </Select>
486
+ `;
487
+ static defaults() {
488
+ return {
489
+ list: []
490
+ }
491
+ }
492
+ private Select = Select;
493
+ private Option = Option;
494
+ }
495
+ const [instance, element] = mount(Demo);
496
+ await wait();
497
+
498
+ // simulate async data loading
499
+ instance.set('list', Array.from({length: 100}, (_, i) => i));
500
+ await wait(100);
501
+
502
+ element.click();
503
+ await wait();
504
+ const wrapper = getElement('.k-virtual-wrapper');
505
+ const phantom = getElement('.k-virtual-phantom');
506
+
507
+ expect(wrapper!.children.length).to.be.equal(10);
508
+ expect(phantom!.style.height).to.be.equal('3000px');
509
+ });
510
+
331
511
  // it('should trigger change event correctly', async () => {
332
512
  // const spy = sinon.spy();
333
513
 
@@ -9,6 +9,7 @@ export interface OptionProps {
9
9
  value: any
10
10
  label?: string
11
11
  disabled?: boolean
12
+ isCreated?: boolean
12
13
  }
13
14
 
14
15
  const typeDefs: Required<TypeDefs<OptionProps>> = {
@@ -17,6 +18,7 @@ const typeDefs: Required<TypeDefs<OptionProps>> = {
17
18
  },
18
19
  label: String,
19
20
  disabled: Boolean,
21
+ isCreated: Boolean,
20
22
  };
21
23
 
22
24
  export class Option extends Component<OptionProps> {
@@ -29,13 +31,19 @@ export class Option extends Component<OptionProps> {
29
31
  @bind
30
32
  private onSelect() {
31
33
  const select = this.select!;
32
- const multiple = select.get('multiple');
34
+ const {multiple, keepKeywords} = select.get();
33
35
  const value = this.get('value');
36
+ const isCreated = this.get('isCreated');
34
37
 
35
38
  if (!multiple) {
36
39
  select.set('value', this.get('value'));
37
40
  } else {
38
41
  let values = select.get('value');
42
+
43
+ if (keepKeywords && isCreated && Array.isArray(values) && values.includes(value)) {
44
+ return;
45
+ }
46
+
39
47
  values = toggleArray(values, value);
40
48
  select.set('value', values);
41
49
  }
@@ -21,6 +21,7 @@ export interface SelectProps<T = string, Multipe extends boolean = boolean> exte
21
21
  labelMap?: Map<any, Children>
22
22
  card?: boolean
23
23
  autoDisableArrow?: boolean
24
+ keepKeywords?: boolean
24
25
  }
25
26
 
26
27
  export interface SelectEvents extends BaseSelectEvents { }
@@ -37,6 +38,7 @@ const typeDefs: Required<TypeDefs<SelectProps>> = {
37
38
  labelMap: Map,
38
39
  card: Boolean,
39
40
  autoDisableArrow: Boolean,
41
+ keepKeywords: Boolean,
40
42
  };
41
43
 
42
44
  const defaults = (): Partial<SelectProps> => ({
@@ -35,7 +35,7 @@ export function useFilterable(keywords: State<string>) {
35
35
  }
36
36
  return false;
37
37
  })) {
38
- return h(Option, {value: _keywords, label: _keywords});
38
+ return h(Option, {value: _keywords, label: _keywords, isCreated: true});
39
39
  }
40
40
  }
41
41
  }
@@ -56,14 +56,16 @@ export function useInput(resetKeywords: (keywords: State<string>) => void) {
56
56
  }
57
57
  });
58
58
  component.on('$changed:value', () => {
59
- const {multiple, filterable} = component.get();
59
+ const {multiple, filterable, keepKeywords} = component.get();
60
60
  if (multiple && filterable) {
61
61
  focusInput();
62
62
  /**
63
63
  * don't reset keywords on multiple mode for continue selection
64
64
  * https://github.com/ksc-fe/kpc/issues/983
65
65
  */
66
- // resetKeywords(keywords);
66
+ if (keepKeywords) {
67
+ resetKeywords(keywords);
68
+ }
67
69
  }
68
70
  });
69
71
 
@@ -47,8 +47,8 @@ export function useSearchable() {
47
47
  }
48
48
 
49
49
  select.watch('value', initCheckedKeys);
50
- select.on('hide', initCheckedKeys)
51
-
50
+ select.on('hide', initCheckedKeys);
51
+ initCheckedKeys();
52
52
  return {checkedKeys, selectAll, unselectAll, toggleSelect, confirm};
53
53
  }
54
54
 
@@ -71,7 +71,8 @@ const hasData = data && data.length;
71
71
 
72
72
  const hasFixedLeft = getHasFixedLeft();
73
73
  const {getAllCheckedStatus, toggleCheckedAll, getAllStatus, onChangeChecked} = this.checked;
74
- const allCheckedStatus = getAllCheckedStatus();
74
+ const allCheckedStatus = getAllCheckedStatus();
75
+ const allStatus = getAllStatus();
75
76
  const thead = hideHeader ? null : (
76
77
  <TableContext.Provider value={{checkType, lastCellKey, lastCellStyle}}>
77
78
  <GroupContext.Provider value={{group, onChange: this.onChangeGroup}}>
@@ -93,7 +94,7 @@ const thead = hideHeader ? null : (
93
94
  value={allCheckedStatus === AllCheckedStatus.All}
94
95
  indeterminate={showIndeterminate && allCheckedStatus == AllCheckedStatus.Indeterminate}
95
96
  ev-$change:value={toggleCheckedAll}
96
- disabled={!hasData}
97
+ disabled={!hasData || allStatus.every(_it => _it.disabled)}
97
98
  />
98
99
  </th>
99
100
  {$value}
@@ -114,7 +115,6 @@ const thead = hideHeader ? null : (
114
115
 
115
116
  const {getAllKeys} = this.disableRow;
116
117
  const {getGrid} = this.merge;
117
- const allStatus = getAllStatus();
118
118
  const allKeys = getAllKeys();
119
119
  const colCount = maxCols + (checkType !== 'none' ? 1 : 0);
120
120
  const {isExpanded} = this.expandable;
@@ -6,7 +6,7 @@ order: 2
6
6
  当指定了`step`属性时,组件将展示成`Select`样式,只能选择固定的几个时间点。通过`min`和`max`限定
7
7
  选择时间范围(默认:00:00:00 ~ 23:59:59),`step`指定步长,它们值类型都为时间字符串
8
8
 
9
- > 可以通过`showFomart`或`format`来格式化时间字符串,来隐藏“秒”
9
+ > 可以通过`showFormat`或`format`来格式化时间字符串,来隐藏“秒”
10
10
 
11
11
  ```vdt
12
12
  import {Timepicker} from 'kpc';
@@ -8,13 +8,14 @@ import {PanelFlags} from '../datepicker/usePanel';
8
8
  import {last} from '../datepicker/helpers';
9
9
  import {ScrollSelect} from '../scrollSelect';
10
10
 
11
- const {className, range, multiple} = this.get();
11
+ const {className, range, multiple, min, max} = this.get();
12
12
  const {
13
13
  value: {value},
14
14
  onConfirm,
15
15
  onChangeTime,
16
16
  onChangeTimeByStep,
17
17
  getTimeValue,
18
+ setMoment,
18
19
  } = this.value;
19
20
  const lastValue = last(value);
20
21
  const { k } = this.config;
@@ -65,6 +66,9 @@ const generatePanel = flag => {
65
66
  {range ? generatePanel(PanelFlags.End) : null}
66
67
  </div>
67
68
  <div class={`${k}-datepicker-footer`}>
69
+ <Button v-if={!range && !multiple && !max && !min} type="link" size="small"
70
+ ev-click={setMoment}
71
+ >{_$('此刻')}</Button>
68
72
  <Button type="primary" size="small"
69
73
  disabled={isDisabledConfirm()}
70
74
  ev-click={onConfirm}
@@ -40,7 +40,6 @@ export const makePanelStyles = cache(function makePanelStyles(k: string) {
40
40
  &.${k}-range {
41
41
  .${k}-datepicker-time {
42
42
  width: auto;
43
- border: ${timepicker.border};
44
43
  }
45
44
  .${k}-scroll-select {
46
45
  height: ${timepicker.range.scrollHeight};
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: 基础用法
3
+ order: 0
4
+ ---
5
+
6
+ ```vdt
7
+ import {Tour, Button} from 'kpc';
8
+
9
+ <div>
10
+ <div class="example-container">
11
+ <Button id="btn1">示例元素1</Button>
12
+ <Button id="btn2" style="margin-left: 20px;">示例元素2</Button>
13
+ </div>
14
+ <Tour
15
+ v-model="currentStep"
16
+ visible={this.get('showTour')}
17
+ data={this.get('tourData')}
18
+ ev-finish={this.close}
19
+ />
20
+ <div style="margin-top: 20px;">
21
+ <Button ev-click={this.settour}>
22
+ 启动引导
23
+ </Button>
24
+ <span style="margin-left: 10px;">
25
+ 当前步骤: {this.get('currentStep') >= 0 ? this.get('currentStep') + 1 : '未启动'}
26
+ </span>
27
+ </div>
28
+ </div>
29
+ ```
30
+
31
+ ```ts
32
+ import {bind} from 'kpc';
33
+ import {TourStepProps} from 'kpc';
34
+
35
+ export default class extends Component {
36
+ static template = template;
37
+ static defaults() {
38
+ return {
39
+ currentStep: 0 as number,
40
+ showTour: false, // 默认不显示
41
+ tourData: [
42
+ {
43
+ target: '#btn1',
44
+ title: '第一步',
45
+ content: '这是第一步的引导说明',
46
+ position: 'bottom'
47
+ },
48
+ {
49
+ target: '#btn2',
50
+ title: '第二步',
51
+ content: '这是第二步的引导说明',
52
+ position: 'right'
53
+ }
54
+ ]
55
+ };
56
+ }
57
+
58
+ @bind
59
+ settour() {
60
+ this.set({
61
+ showTour: true,
62
+ currentStep: 0
63
+ });
64
+ }
65
+
66
+ @bind
67
+ close() {
68
+ this.set({
69
+ showTour: false
70
+ });
71
+ }
72
+ }
73
+ ```
@@ -0,0 +1,109 @@
1
+ ---
2
+ title: 步骤控制
3
+ order: 3
4
+ ---
5
+
6
+ ```vdt
7
+ import {Tour, Button, Input} from 'kpc';
8
+
9
+ <div>
10
+ <div class="example-container">
11
+ <Button id="step1">步骤1</Button>
12
+ <Button id="step2" style="margin-left: 20px;">步骤2</Button>
13
+ <div style="margin-top: 20px;">
14
+ <Input class="step3-input" placeholder="通过验证才能进入下一步" v-model="inputValue" />
15
+ </div>
16
+ <Button id="step4" style="margin-top: 20px;">步骤4</Button>
17
+ </div>
18
+
19
+ <Tour
20
+ v-model="currentStep"
21
+ visible={this.get('showTour')}
22
+ data={this.get('tourData')}
23
+ beforeChange={this.handleBeforeChange}
24
+ ev-finish={this.finishTour}
25
+ />
26
+
27
+ <div style="margin-top: 20px;">
28
+ <Button ev-click={this.startTour}>
29
+ 启动引导
30
+ </Button>
31
+ <span style="margin-left: 10px;">
32
+ 当前步骤: {this.get('currentStep') >= 0 ? this.get('currentStep') + 1 : '未启动'}
33
+ </span>
34
+ <div style="margin-top: 10px; color: #f56c6c" v-if={this.get('errorMsg')}>
35
+ {this.get('errorMsg')}
36
+ </div>
37
+ </div>
38
+ </div>
39
+ ```
40
+
41
+ ```ts
42
+ import {bind, Message} from 'kpc';
43
+
44
+ export default class extends Component {
45
+ static template = template;
46
+ static defaults() {
47
+ return {
48
+ currentStep: 0,
49
+ showTour: false,
50
+ inputValue: '',
51
+ errorMsg: '',
52
+ tourData: [
53
+ {
54
+ target: '#step1',
55
+ title: '第一步',
56
+ content: '这是第一步的引导说明',
57
+ position: 'bottom'
58
+ },
59
+ {
60
+ target: '#step2',
61
+ title: '第二步',
62
+ content: '这是第二步的引导说明',
63
+ position: 'right'
64
+ },
65
+ {
66
+ target: '.step3-input',
67
+ title: '第三步',
68
+ content: '请在输入框中输入"next"以继续',
69
+ position: 'bottom'
70
+ },
71
+ {
72
+ target: '#step4',
73
+ title: '最后一步',
74
+ content: '恭喜您完成了所有步骤',
75
+ position: 'top'
76
+ }
77
+ ]
78
+ };
79
+ }
80
+
81
+ @bind
82
+ startTour() {
83
+ this.set({
84
+ showTour: true,
85
+ currentStep: 0,
86
+ });
87
+ }
88
+
89
+ @bind
90
+ finishTour() {
91
+ this.set({
92
+ showTour: false
93
+ });
94
+ }
95
+
96
+
97
+ @bind
98
+ handleBeforeChange(current: number) {
99
+ const inputValue = this.get('inputValue') as string;
100
+ if (current === 3) {
101
+ if (inputValue !== 'next') {
102
+ Message.error('请在输入框中输入"next"才能进入下一步');
103
+ return false;
104
+ }
105
+ }
106
+ return true;
107
+ }
108
+ }
109
+ ```