@king-design/intact 3.5.2 → 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 (260) hide show
  1. package/components/.DS_Store +0 -0
  2. package/components/button/index.md +1 -0
  3. package/components/cascader/index.spec.ts +7 -6
  4. package/components/datepicker/basepicker.ts +26 -267
  5. package/components/datepicker/calendar.ts +8 -2
  6. package/components/datepicker/calendar.vdt +23 -6
  7. package/components/datepicker/dayjs.ts +8 -2
  8. package/components/datepicker/demos/multiple.md +1 -1
  9. package/components/datepicker/demos/yearMonth.md +1 -1
  10. package/components/datepicker/helpers.ts +10 -12
  11. package/components/datepicker/index.md +2 -2
  12. package/components/datepicker/index.spec.ts +619 -190
  13. package/components/datepicker/index.ts +22 -21
  14. package/components/datepicker/index.vdt +47 -42
  15. package/components/datepicker/shortcuts.ts +1 -1
  16. package/components/datepicker/styles.ts +112 -4
  17. package/components/datepicker/useConfirm.ts +82 -0
  18. package/components/datepicker/useDisabled.ts +31 -33
  19. package/components/datepicker/useFormats.ts +10 -4
  20. package/components/datepicker/useHighlight.ts +81 -0
  21. package/components/datepicker/useKeyboards.ts +2 -1
  22. package/components/datepicker/useMergeRange.ts +54 -0
  23. package/components/datepicker/useMonths.ts +6 -3
  24. package/components/datepicker/usePanel.ts +19 -19
  25. package/components/datepicker/useQuarters.ts +47 -0
  26. package/components/datepicker/useShowDate.ts +14 -3
  27. package/components/datepicker/useStatus.ts +34 -15
  28. package/components/datepicker/useValue.ts +41 -39
  29. package/components/datepicker/useValueBase.ts +309 -0
  30. package/components/datepicker/useWeeks.ts +58 -0
  31. package/components/datepicker/useYears.ts +7 -3
  32. package/components/descriptions/.DS_Store +0 -0
  33. package/components/dialog/useFixBody.ts +7 -64
  34. package/components/dropdown/dropdown.ts +5 -4
  35. package/components/dropdown/index.md +1 -0
  36. package/components/dropdown/item.ts +1 -1
  37. package/components/dropdown/useKeyboard.ts +0 -1
  38. package/components/ellipsis/styles.ts +4 -0
  39. package/components/form/styles.ts +1 -0
  40. package/components/input/index.spec.ts +42 -0
  41. package/components/input/index.ts +8 -0
  42. package/components/input/index.vdt +3 -4
  43. package/components/input/useAutoWidth.ts +19 -1
  44. package/components/menu/.DS_Store +0 -0
  45. package/components/menu/demos/.DS_Store +0 -0
  46. package/components/scrollSelect/index.spec.ts +3 -3
  47. package/components/scrollSelect/useMouseEvents.ts +24 -10
  48. package/components/select/base.ts +3 -2
  49. package/components/select/base.vdt +3 -1
  50. package/components/select/demos/creatable.md +13 -0
  51. package/components/select/index.md +1 -0
  52. package/components/select/index.spec.ts +225 -6
  53. package/components/select/option.ts +10 -1
  54. package/components/select/select.ts +3 -0
  55. package/components/select/styles.ts +3 -1
  56. package/components/select/useFilterable.ts +1 -1
  57. package/components/select/useInput.ts +7 -9
  58. package/components/select/useSearchable.ts +2 -2
  59. package/components/table/.DS_Store +0 -0
  60. package/components/table/index.spec.ts +69 -1
  61. package/components/table/useStickyHeader.ts +1 -1
  62. package/components/timepicker/demos/step.md +1 -1
  63. package/components/timepicker/index.spec.ts +145 -27
  64. package/components/timepicker/panelPicker.ts +10 -4
  65. package/components/timepicker/panelPicker.vdt +5 -3
  66. package/components/timepicker/useConfirm.ts +33 -0
  67. package/components/timepicker/useDefaultValue.ts +30 -0
  68. package/components/timepicker/useDisabled.ts +17 -4
  69. package/components/timepicker/useFormats.ts +1 -1
  70. package/components/timepicker/useValue.ts +22 -19
  71. package/components/tour/.DS_Store +0 -0
  72. package/components/tour/demos/basic.md +73 -0
  73. package/components/tour/demos/beforeChange.md +109 -0
  74. package/components/tour/demos/closable.md +70 -0
  75. package/components/tour/demos/custom.md +98 -0
  76. package/components/tour/demos/customText.md +94 -0
  77. package/components/tour/demos/declarative.md +72 -0
  78. package/components/tour/demos/events.md +101 -0
  79. package/components/tour/demos/maskClosable.md +76 -0
  80. package/components/tour/demos/notarget.md +59 -0
  81. package/components/tour/index.md +48 -0
  82. package/components/tour/index.spec.ts +259 -0
  83. package/components/tour/index.ts +2 -0
  84. package/components/tour/step.ts +55 -0
  85. package/components/tour/step.vdt +75 -0
  86. package/components/tour/styles.ts +283 -0
  87. package/components/tour/tour.ts +107 -0
  88. package/components/tour/tour.vdt +83 -0
  89. package/components/tour/useArrow.ts +46 -0
  90. package/components/tour/useFixBody.ts +22 -0
  91. package/components/tour/useHighlight.ts +36 -0
  92. package/components/tour/useMaskClosable.ts +26 -0
  93. package/components/tour/useNavigation.ts +46 -0
  94. package/components/tour/usePosition.ts +91 -0
  95. package/components/tour/useSteps.ts +80 -0
  96. package/components/virtualList/.DS_Store +0 -0
  97. package/components/virtualList/demos/.DS_Store +0 -0
  98. package/es/components/cascader/index.spec.js +18 -19
  99. package/es/components/datepicker/basepicker.d.ts +6 -25
  100. package/es/components/datepicker/basepicker.js +22 -234
  101. package/es/components/datepicker/calendar.d.ts +36 -6
  102. package/es/components/datepicker/calendar.js +4 -0
  103. package/es/components/datepicker/calendar.vdt.js +21 -5
  104. package/es/components/datepicker/dayjs.d.ts +2 -2
  105. package/es/components/datepicker/dayjs.js +6 -0
  106. package/es/components/datepicker/helpers.d.ts +8 -7
  107. package/es/components/datepicker/helpers.js +2 -3
  108. package/es/components/datepicker/index.d.ts +26 -19
  109. package/es/components/datepicker/index.js +21 -13
  110. package/es/components/datepicker/index.spec.js +1389 -633
  111. package/es/components/datepicker/index.vdt.js +43 -46
  112. package/es/components/datepicker/shortcuts.d.ts +1 -1
  113. package/es/components/datepicker/styles.d.ts +22 -0
  114. package/es/components/datepicker/styles.js +26 -4
  115. package/es/components/datepicker/useConfirm.d.ts +6 -0
  116. package/es/components/datepicker/useConfirm.js +65 -0
  117. package/es/components/datepicker/useDisabled.d.ts +7 -5
  118. package/es/components/datepicker/useDisabled.js +22 -27
  119. package/es/components/datepicker/useFormats.d.ts +2 -2
  120. package/es/components/datepicker/useFormats.js +9 -3
  121. package/es/components/datepicker/useHighlight.d.ts +14 -0
  122. package/es/components/datepicker/useHighlight.js +60 -0
  123. package/es/components/datepicker/useKeyboards.js +2 -1
  124. package/es/components/datepicker/useMergeRange.d.ts +5 -0
  125. package/es/components/datepicker/useMergeRange.js +45 -0
  126. package/es/components/datepicker/useMonths.js +5 -3
  127. package/es/components/datepicker/usePanel.d.ts +1 -10
  128. package/es/components/datepicker/usePanel.js +19 -32
  129. package/es/components/datepicker/useQuarters.d.ts +15 -0
  130. package/es/components/datepicker/useQuarters.js +36 -0
  131. package/es/components/datepicker/useShowDate.js +10 -2
  132. package/es/components/datepicker/useStatus.d.ts +1 -1
  133. package/es/components/datepicker/useStatus.js +33 -16
  134. package/es/components/datepicker/useValue.d.ts +12 -6
  135. package/es/components/datepicker/useValue.js +49 -45
  136. package/es/components/datepicker/useValueBase.d.ts +28 -0
  137. package/es/components/datepicker/useValueBase.js +277 -0
  138. package/es/components/datepicker/useWeeks.d.ts +19 -0
  139. package/es/components/datepicker/useWeeks.js +48 -0
  140. package/es/components/datepicker/useYears.js +6 -3
  141. package/es/components/dialog/useFixBody.js +6 -58
  142. package/es/components/dropdown/dropdown.d.ts +1 -0
  143. package/es/components/dropdown/dropdown.js +7 -4
  144. package/es/components/ellipsis/styles.js +1 -1
  145. package/es/components/form/styles.js +1 -1
  146. package/es/components/input/index.d.ts +2 -0
  147. package/es/components/input/index.js +6 -0
  148. package/es/components/input/index.spec.js +45 -0
  149. package/es/components/input/index.vdt.js +4 -3
  150. package/es/components/input/useAutoWidth.d.ts +2 -0
  151. package/es/components/input/useAutoWidth.js +19 -1
  152. package/es/components/scrollSelect/index.spec.js +4 -6
  153. package/es/components/scrollSelect/useMouseEvents.js +22 -9
  154. package/es/components/select/base.d.ts +1 -1
  155. package/es/components/select/base.js +3 -2
  156. package/es/components/select/base.vdt.js +5 -2
  157. package/es/components/select/index.spec.js +329 -82
  158. package/es/components/select/option.d.ts +1 -0
  159. package/es/components/select/option.js +10 -2
  160. package/es/components/select/select.d.ts +1 -0
  161. package/es/components/select/select.js +4 -2
  162. package/es/components/select/styles.d.ts +79 -0
  163. package/es/components/select/styles.js +1 -0
  164. package/es/components/select/useFilterable.js +2 -1
  165. package/es/components/select/useInput.d.ts +1 -1
  166. package/es/components/select/useInput.js +7 -4
  167. package/es/components/select/useSearchable.js +1 -0
  168. package/es/components/table/index.spec.js +84 -6
  169. package/es/components/table/useStickyHeader.js +1 -1
  170. package/es/components/timepicker/index.spec.js +298 -128
  171. package/es/components/timepicker/panelPicker.d.ts +23 -17
  172. package/es/components/timepicker/panelPicker.js +7 -4
  173. package/es/components/timepicker/panelPicker.vdt.js +8 -4
  174. package/es/components/timepicker/selectPicker.d.ts +5 -4
  175. package/es/components/timepicker/useConfirm.d.ts +6 -0
  176. package/es/components/timepicker/useConfirm.js +19 -0
  177. package/es/components/timepicker/useDefaultValue.d.ts +4 -0
  178. package/es/components/timepicker/useDefaultValue.js +27 -0
  179. package/es/components/timepicker/useDisabled.d.ts +7 -4
  180. package/es/components/timepicker/useDisabled.js +13 -4
  181. package/es/components/timepicker/useFormats.d.ts +1 -1
  182. package/es/components/timepicker/useValue.d.ts +14 -8
  183. package/es/components/timepicker/useValue.js +14 -15
  184. package/es/components/tour/index.d.ts +2 -0
  185. package/es/components/tour/index.js +2 -0
  186. package/es/components/tour/index.spec.d.ts +1 -0
  187. package/es/components/tour/index.spec.js +356 -0
  188. package/es/components/tour/step.d.ts +23 -0
  189. package/es/components/tour/step.js +46 -0
  190. package/es/components/tour/step.vdt.js +74 -0
  191. package/es/components/tour/styles.d.ts +7 -0
  192. package/es/components/tour/styles.js +84 -0
  193. package/es/components/tour/tour.d.ts +73 -0
  194. package/es/components/tour/tour.js +70 -0
  195. package/es/components/tour/tour.vdt.js +66 -0
  196. package/es/components/tour/useArrow.d.ts +4 -0
  197. package/es/components/tour/useArrow.js +40 -0
  198. package/es/components/tour/useFixBody.d.ts +4 -0
  199. package/es/components/tour/useFixBody.js +17 -0
  200. package/es/components/tour/useHighlight.d.ts +4 -0
  201. package/es/components/tour/useHighlight.js +31 -0
  202. package/es/components/tour/useMaskClosable.d.ts +1 -0
  203. package/es/components/tour/useMaskClosable.js +25 -0
  204. package/es/components/tour/useNavigation.d.ts +5 -0
  205. package/es/components/tour/useNavigation.js +103 -0
  206. package/es/components/tour/usePosition.d.ts +6 -0
  207. package/es/components/tour/usePosition.js +93 -0
  208. package/es/components/tour/useSteps.d.ts +6 -0
  209. package/es/components/tour/useSteps.js +68 -0
  210. package/es/hooks/useFixBody.d.ts +11 -0
  211. package/es/hooks/useFixBody.js +72 -0
  212. package/es/index.d.ts +3 -2
  213. package/es/index.js +3 -2
  214. package/es/site/data/components/datepicker/demos/multiple/react.js +2 -2
  215. package/es/site/data/components/select/demos/creatable/index.d.ts +1 -0
  216. package/es/site/data/components/select/demos/creatable/index.js +2 -1
  217. package/es/site/data/components/select/demos/creatable/react.d.ts +1 -0
  218. package/es/site/data/components/select/demos/creatable/react.js +31 -2
  219. package/es/site/data/components/tour/demos/basic/index.d.ts +17 -0
  220. package/es/site/data/components/tour/demos/basic/index.js +46 -0
  221. package/es/site/data/components/tour/demos/basic/react.d.ts +16 -0
  222. package/es/site/data/components/tour/demos/basic/react.js +82 -0
  223. package/es/site/data/components/tour/demos/beforeChange/index.d.ts +20 -0
  224. package/es/site/data/components/tour/demos/beforeChange/index.js +69 -0
  225. package/es/site/data/components/tour/demos/beforeChange/react.d.ts +19 -0
  226. package/es/site/data/components/tour/demos/beforeChange/react.js +129 -0
  227. package/es/site/data/components/tour/demos/closable/index.d.ts +18 -0
  228. package/es/site/data/components/tour/demos/closable/index.js +42 -0
  229. package/es/site/data/components/tour/demos/closable/react.d.ts +17 -0
  230. package/es/site/data/components/tour/demos/closable/react.js +85 -0
  231. package/es/site/data/components/tour/demos/custom/index.d.ts +11 -0
  232. package/es/site/data/components/tour/demos/custom/index.js +35 -0
  233. package/es/site/data/components/tour/demos/custom/react.d.ts +11 -0
  234. package/es/site/data/components/tour/demos/custom/react.js +108 -0
  235. package/es/site/data/components/tour/demos/customText/index.d.ts +33 -0
  236. package/es/site/data/components/tour/demos/customText/index.js +55 -0
  237. package/es/site/data/components/tour/demos/customText/react.d.ts +33 -0
  238. package/es/site/data/components/tour/demos/customText/react.js +99 -0
  239. package/es/site/data/components/tour/demos/declarative/index.d.ts +11 -0
  240. package/es/site/data/components/tour/demos/declarative/index.js +36 -0
  241. package/es/site/data/components/tour/demos/declarative/react.d.ts +10 -0
  242. package/es/site/data/components/tour/demos/declarative/react.js +80 -0
  243. package/es/site/data/components/tour/demos/events/index.d.ts +18 -0
  244. package/es/site/data/components/tour/demos/events/index.js +58 -0
  245. package/es/site/data/components/tour/demos/events/react.d.ts +18 -0
  246. package/es/site/data/components/tour/demos/events/react.js +101 -0
  247. package/es/site/data/components/tour/demos/maskClosable/index.d.ts +18 -0
  248. package/es/site/data/components/tour/demos/maskClosable/index.js +47 -0
  249. package/es/site/data/components/tour/demos/maskClosable/react.d.ts +17 -0
  250. package/es/site/data/components/tour/demos/maskClosable/react.js +95 -0
  251. package/es/site/data/components/tour/demos/notarget/index.d.ts +11 -0
  252. package/es/site/data/components/tour/demos/notarget/index.js +35 -0
  253. package/es/site/data/components/tour/demos/notarget/react.d.ts +10 -0
  254. package/es/site/data/components/tour/demos/notarget/react.js +61 -0
  255. package/es/site/data/components/tour/index.d.ts +57 -0
  256. package/es/site/data/components/tour/index.js +32 -0
  257. package/hooks/useFixBody.ts +87 -0
  258. package/index.ts +3 -2
  259. package/package.json +2 -2
  260. package/styles/.DS_Store +0 -0
@@ -6,6 +6,7 @@ export function useAutoWidth() {
6
6
  const instance = useInstance() as Input;
7
7
  const fakeRef = createRef<HTMLDivElement>();
8
8
  const width = useState<number>(0);
9
+ const forceShowFake = useState(false);
9
10
 
10
11
  instance.watch('value', adjustWidth, {inited: true, presented: true});
11
12
  instance.watch('placeholder', adjustWidth, {inited: true, presented: true});
@@ -23,7 +24,24 @@ export function useAutoWidth() {
23
24
  }
24
25
  }
25
26
 
26
- return {fakeRef, width};
27
+ function getStringWidth(str: string) {
28
+ forceShowFake.set(true);
29
+ return new Promise<number>((resolve) => {
30
+ nextTick(() => {
31
+ const fakeElem = fakeRef.value!;
32
+ const textNode = fakeElem.firstChild!;
33
+ const oldStr = textNode.nodeValue;
34
+ textNode.nodeValue = str;
35
+
36
+ resolve(fakeElem.offsetWidth);
37
+
38
+ textNode.nodeValue = oldStr;
39
+ forceShowFake.set(false);
40
+ });
41
+ });
42
+ }
43
+
44
+ return {fakeRef, width, forceShowFake, getStringWidth};
27
45
  }
28
46
 
29
47
  function isVisible(elem: HTMLDivElement | null) {
Binary file
Binary file
@@ -4,17 +4,17 @@ import {ScrollSelect} from './';
4
4
  import {Component} from 'intact';
5
5
 
6
6
  describe('ScrollSelect', () => {
7
- afterEach(() => unmount());
7
+ // afterEach(() => unmount());
8
8
 
9
9
  it('should select by scroll', async () => {
10
10
  const [instance, element] = mount(BasicDemo);
11
11
 
12
12
  // scroll
13
- dispatchEvent(element.firstElementChild!, 'wheel', {deltaY: 1});
13
+ dispatchEvent(element.firstElementChild!, 'wheel', {deltaY: 30});
14
14
  await wait(100);
15
15
  expect(instance.get('value')).to.eql(1);
16
16
 
17
- dispatchEvent(element.firstElementChild!, 'wheel', {deltaY: -1});
17
+ dispatchEvent(element.firstElementChild!, 'wheel', {deltaY: -30});
18
18
  await wait(100);
19
19
  expect(instance.get('value')).to.eql(0);
20
20
  });
@@ -18,6 +18,7 @@ export function useMouseEvents(
18
18
  let y: number;
19
19
  let itemHeight: number;
20
20
  let deltaY: number;
21
+ let wheelDeltaY: number = 0;
21
22
  const {start, dragging} = useDraggable({
22
23
  onStart(e: MouseEvent) {
23
24
  dragged = false;
@@ -28,12 +29,12 @@ export function useMouseEvents(
28
29
  },
29
30
 
30
31
  onMove(e: MouseEvent) {
31
- const deltaY = e.clientY - y;
32
+ const deltaY = (e.clientY - y) * 0.8;
32
33
  dragged = !!deltaY;
33
34
  y = e.clientY;
34
35
 
35
36
  const _deltaY = y - initY;
36
- let offsetIndex = Math.floor(Math.abs(_deltaY) / itemHeight);
37
+ let offsetIndex = Math.floor(Math.abs(_deltaY) / itemHeight * 1.2);
37
38
  if (offsetIndex) {
38
39
  if (_deltaY < 0) {
39
40
  offsetIndex = -offsetIndex;
@@ -63,25 +64,38 @@ export function useMouseEvents(
63
64
 
64
65
  function onWheel(e: WheelEvent) {
65
66
  e.preventDefault();
66
- itemHeight = getItemHeight();
67
- if (e.deltaY > 0) {
68
- // down
69
- setByRelativeIndex(1, null, true);
70
- } else {
71
- setByRelativeIndex(-1, null, true);
67
+
68
+ itemHeight = getItemHeight();
69
+
70
+ const threshold = itemHeight * 0.6;
71
+ wheelDeltaY += e.deltaY;
72
+
73
+ if (Math.abs(wheelDeltaY) >= threshold) {
74
+ if (wheelDeltaY > 0) {
75
+ setByRelativeIndex(1, null, true);
76
+ } else {
77
+ setByRelativeIndex(-1, null, true);
78
+ }
79
+ wheelDeltaY = 0;
72
80
  }
73
81
  }
74
82
 
75
83
  // throttle onWheel
76
- const _onWheel = throttle(onWheel, 0, e => e.preventDefault());
84
+ const _onWheel = throttle(onWheel, 50, e => e.preventDefault());
77
85
 
78
86
  function onClick(item: any, index: number) {
79
- // if _dragged, do not trigger click event, #123
87
+ // if dragged, do not trigger click event
80
88
  if (dragged) return;
81
89
 
82
90
  const {count} = instance.get();
83
91
  const half = Math.floor(count! / 2);
84
92
  const itemHeight = getItemHeight();
93
+
94
+ const currentIndex = list.data.value.findIndex(v => v.value === list.value.value);
95
+ const targetOffset = index - half;
96
+ if (currentIndex + targetOffset < 0 || currentIndex + targetOffset >= list.data.value.length) {
97
+ return;
98
+ }
85
99
 
86
100
  translate.set(translate.value - itemHeight * (index - half));
87
101
  marginTop.set(marginTop.value + itemHeight * (index - half));
@@ -142,8 +142,9 @@ export abstract class BaseSelect<
142
142
  this.set('show', false);
143
143
  }
144
144
 
145
- public resetKeywords(keywords: State<string>) {
146
- keywords.set('');
145
+ @bind
146
+ public resetKeywords() {
147
+ this.input.keywords.set('');
147
148
  }
148
149
 
149
150
  protected hasValue() {
@@ -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
 
@@ -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 />
@@ -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={false} 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=false: {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` | `true` |
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` |
@@ -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,29 +216,157 @@ 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');
287
+ });
288
+
289
+ it('keepKeywords', async () => {
290
+ class KeepKeywordsDemo extends Component<{days: string[]}> {
291
+ static template = `
292
+ const {Select, Option} = this;
293
+ <div>
294
+ <Select v-model="days" filterable multiple creatable keepKeywords={false}>
295
+ <Option value="Monday">星期一</Option>
296
+ <Option value="Tuesday">星期二</Option>
297
+ <Option value="Wednesday">星期三</Option>
298
+ </Select>
299
+ </div>
300
+ `;
301
+ static defaults() {
302
+ return {
303
+ days: [] as string[],
304
+ };
305
+ }
306
+ private Select = Select as any;
307
+ private Option = Option as any;
308
+ }
309
+
310
+ const [instance, element] = mount(KeepKeywordsDemo);
311
+ const input = element.querySelector('.k-input-inner') as HTMLInputElement;
312
+
313
+ // input custom option "custom1"
314
+ input.click();
315
+ await wait();
316
+ input.value = 'custom1';
317
+ dispatchEvent(input, 'input');
318
+ await wait();
319
+
320
+ // check the created option appears in dropdown
321
+ const dropdown = getElement('.k-select-menu')!;
322
+ expect(dropdown.innerHTML).to.contain('custom1');
323
+
324
+ // press enter to create and select
325
+ dispatchEvent(document, 'keydown', {keyCode: 13});
326
+ await wait();
327
+
328
+ // check the option is selected, and the input is cleared
329
+ expect(instance.get('days')).to.eql(['custom1']);
330
+ expect(input.value).to.eql('');
331
+
332
+ // input the same option "custom1" again
333
+ input.value = 'custom1';
334
+ dispatchEvent(input, 'input');
335
+ await wait();
336
+
337
+ // press enter again
338
+ dispatchEvent(document, 'keydown', {keyCode: 13});
339
+ await wait();
340
+
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
344
+
345
+ // input another custom option "custom2"
346
+ input.value = 'custom2';
347
+ dispatchEvent(input, 'input');
348
+ await wait();
349
+ dispatchEvent(document, 'keydown', {keyCode: 13});
350
+ await wait();
351
+
352
+ // check two options are selected
353
+ expect(instance.get('days')).to.eql(['custom1', 'custom2']);
354
+ expect(input.value).to.eql('');
355
+
356
+ // test the normal behavior of original options
357
+ input.click();
358
+ await wait();
359
+ const mondayOption = dropdown.querySelector('[data-value="Monday"]') as HTMLElement;
360
+ if (mondayOption) {
361
+ mondayOption.click();
362
+ await wait();
363
+ expect(instance.get('days')).to.include('Monday');
364
+
365
+ // click again should be unselected (original options are not affected by keepKeywords)
366
+ mondayOption.click();
367
+ await wait();
368
+ expect(instance.get('days')).to.not.include('Monday');
369
+ }
239
370
  });
240
371
 
241
372
  it('Tooltip with Select', async () => {
@@ -298,6 +429,94 @@ describe('Select', () => {
298
429
  expect(instance.get('days')).include('Monday')
299
430
  });
300
431
 
432
+ it('Searchable with multiple should show correct initial checkbox state', async () => {
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);
462
+
463
+ expect(instance.get('days')).to.eql(['Tuesday']);
464
+
465
+ // first open dropdown, check initial state
466
+ element.click();
467
+ await wait();
468
+
469
+ const dropdown = getElement('.k-select-menu')!;
470
+ const checkboxes = dropdown.querySelectorAll<HTMLInputElement>('.k-checkbox input[type="checkbox"]');
471
+ const options = dropdown.querySelectorAll<HTMLElement>('.k-select-option');
472
+
473
+ // find the checkbox of Tuesday option
474
+ let tuesdayCheckbox: HTMLInputElement | null = null;
475
+ let tuesdayOption: HTMLElement | null = null;
476
+
477
+ options.forEach((option, index) => {
478
+ if (option.textContent?.includes('星期二')) {
479
+ tuesdayCheckbox = checkboxes[index];
480
+ tuesdayOption = option;
481
+ }
482
+ });
483
+
484
+ // check the checkbox of Tuesday should be checked
485
+ expect(tuesdayCheckbox).to.exist;
486
+ expect(tuesdayCheckbox!.checked).to.be.true;
487
+
488
+ // check the Tuesday option should have active style
489
+ expect(tuesdayOption).to.exist;
490
+ expect(tuesdayOption!.className).to.include('k-active');
491
+
492
+ // close dropdown
493
+ const [cancel] = dropdown.querySelectorAll<HTMLElement>('.k-select-footer .k-btn');
494
+ cancel.click();
495
+ await wait();
496
+
497
+ // reopen dropdown, check the state is still correct
498
+ element.click();
499
+ await wait();
500
+
501
+ const dropdown2 = getElement('.k-select-menu')!;
502
+ const checkboxes2 = dropdown2.querySelectorAll<HTMLInputElement>('.k-checkbox input[type="checkbox"]');
503
+ const options2 = dropdown2.querySelectorAll<HTMLElement>('.k-select-option');
504
+
505
+ let tuesdayCheckbox2: HTMLInputElement | null = null;
506
+ let tuesdayOption2: HTMLElement | null = null;
507
+
508
+ options2.forEach((option, index) => {
509
+ if (option.textContent?.includes('星期二')) {
510
+ tuesdayCheckbox2 = checkboxes2[index];
511
+ tuesdayOption2 = option;
512
+ }
513
+ });
514
+
515
+ // check the state is still correct when reopen
516
+ expect(tuesdayCheckbox2!.checked).to.be.true;
517
+ expect(tuesdayOption2!.className).to.include('k-active');
518
+ });
519
+
301
520
  it('disabled option does not allow clearable and close', async () => {
302
521
  const [instance, element] = mount(ImmutableDemo);
303
522
 
@@ -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,20 @@ 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
+ select.resetKeywords();
45
+ return;
46
+ }
47
+
39
48
  values = toggleArray(values, value);
40
49
  select.set('value', values);
41
50
  }
@@ -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,11 +38,13 @@ 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> => ({
43
45
  ...BaseSelect.defaults(),
44
46
  labelMap: new Map(),
47
+ keepKeywords: true,
45
48
  });
46
49
 
47
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;
@@ -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
  }
@@ -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,20 +46,22 @@ 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', () => {
59
- const {multiple, filterable} = component.get();
55
+ const {multiple, filterable, keepKeywords} = component.get();
60
56
  if (multiple && filterable) {
61
57
  focusInput();
62
58
  /**
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
- // resetKeywords(keywords);
62
+ if (!keepKeywords) {
63
+ resetKeywords();
64
+ }
67
65
  }
68
66
  });
69
67
 
@@ -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
 
Binary file