@king-design/intact 3.6.0 → 3.6.2-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 (59) hide show
  1. package/components/button/demos/basic.md +0 -1
  2. package/components/copy/index.spec.ts +9 -14
  3. package/components/datepicker/index.spec.ts +55 -28
  4. package/components/datepicker/useValueBase.ts +5 -2
  5. package/components/dropdown/constants.ts +25 -0
  6. package/components/dropdown/item.ts +1 -2
  7. package/components/dropdown/menu.ts +1 -1
  8. package/components/dropdown/useItemKeyboard.ts +38 -0
  9. package/components/dropdown/{useKeyboard.ts → useMenuKeyboard.ts} +3 -62
  10. package/components/form/form.ts +4 -0
  11. package/components/form/index.md +2 -1
  12. package/components/form/index.spec.ts +2 -0
  13. package/components/menu/demos/horizontal.md +7 -1
  14. package/components/menu/index.spec.ts +19 -0
  15. package/components/menu/styles.ts +2 -1
  16. package/components/select/index.spec.ts +35 -2
  17. package/components/select/menu.ts +1 -1
  18. package/components/select/useCard.ts +22 -4
  19. package/components/spinner/index.spec.ts +18 -0
  20. package/components/spinner/useValue.ts +2 -1
  21. package/es/components/copy/index.spec.js +14 -31
  22. package/es/components/datepicker/index.spec.js +646 -608
  23. package/es/components/datepicker/useValueBase.js +5 -2
  24. package/es/components/dropdown/constants.d.ts +22 -0
  25. package/es/components/dropdown/constants.js +7 -0
  26. package/es/components/dropdown/item.js +1 -1
  27. package/es/components/dropdown/menu.js +1 -1
  28. package/es/components/dropdown/useItemKeyboard.d.ts +6 -0
  29. package/es/components/dropdown/useItemKeyboard.js +32 -0
  30. package/es/components/dropdown/useMenuKeyboard.d.ts +2 -0
  31. package/es/components/dropdown/{useKeyboard.js → useMenuKeyboard.js} +3 -38
  32. package/es/components/form/form.d.ts +1 -0
  33. package/es/components/form/form.js +7 -0
  34. package/es/components/form/index.spec.js +10 -8
  35. package/es/components/menu/index.spec.js +28 -0
  36. package/es/components/menu/styles.js +2 -2
  37. package/es/components/select/index.spec.js +231 -177
  38. package/es/components/select/menu.js +1 -1
  39. package/es/components/select/useCard.d.ts +4 -3
  40. package/es/components/select/useCard.js +15 -4
  41. package/es/components/spinner/index.spec.js +82 -44
  42. package/es/components/spinner/useValue.js +2 -1
  43. package/es/index.d.ts +2 -2
  44. package/es/index.js +2 -2
  45. package/es/site/data/components/button/demos/basic/react.js +0 -2
  46. package/es/site/data/components/menu/demos/horizontal/react.js +5 -1
  47. package/es/test/demos.js +1 -1
  48. package/index.ts +2 -2
  49. package/package.json +2 -2
  50. package/components/.DS_Store +0 -0
  51. package/components/descriptions/.DS_Store +0 -0
  52. package/components/menu/.DS_Store +0 -0
  53. package/components/menu/demos/.DS_Store +0 -0
  54. package/components/table/.DS_Store +0 -0
  55. package/components/tour/.DS_Store +0 -0
  56. package/components/virtualList/.DS_Store +0 -0
  57. package/components/virtualList/demos/.DS_Store +0 -0
  58. package/es/components/dropdown/useKeyboard.d.ts +0 -23
  59. package/styles/.DS_Store +0 -0
@@ -20,7 +20,6 @@ import {Button} from 'kpc';
20
20
  <Button type="flat">flat</Button>
21
21
  <Button color="red">custom</Button>
22
22
  <Button color="#0000ea">custom</Button>
23
- <Button color="rgb(183, 18, 193)">custom</Button>
24
23
  </div>
25
24
  ```
26
25
 
@@ -10,19 +10,18 @@ describe('Copy', () => {
10
10
  });
11
11
 
12
12
  it('should copy', async function() {
13
+ const spy = sinon.spy(navigator.clipboard, 'writeText');
13
14
  const [instance, element] = mount(BasicDemo);
14
15
 
15
16
  element.click();
16
- try {
17
- const text = await navigator.clipboard.readText();
18
- expect(text).to.eql('Hello King Desgin!');
19
- } catch (e) {
20
- // Read permisson denied
21
- console.log(e);
22
- }
17
+ await wait();
18
+ expect(spy.calledWith('Hello King Desgin!')).to.be.true;
19
+
20
+ spy.restore();
23
21
  });
24
22
 
25
23
  it('wrap copy with tooltip', async () => {
24
+ const spy = sinon.spy(navigator.clipboard, 'writeText');
26
25
  class Demo extends Component {
27
26
  static template = `
28
27
  const { Tooltip, Copy } = this;
@@ -38,12 +37,8 @@ describe('Copy', () => {
38
37
 
39
38
  element.click();
40
39
  await wait();
41
- try {
42
- const text = await navigator.clipboard.readText();
43
- expect(text).to.eql('test');
44
- } catch (e) {
45
- // Read permisson denied
46
- console.log(e);
47
- }
40
+ expect(spy.calledWith('test')).to.be.true;
41
+
42
+ spy.restore();
48
43
  });
49
44
  });
@@ -38,10 +38,10 @@ function getDateString(date: number) {
38
38
  }
39
39
 
40
40
  describe('Datepicker', () => {
41
- // afterEach(async () => {
42
- // unmount();
43
- // await wait(500);
44
- // });
41
+ afterEach(async () => {
42
+ unmount();
43
+ await wait(500);
44
+ });
45
45
 
46
46
  describe('Pick', () => {
47
47
  it('date', async () => {
@@ -151,37 +151,37 @@ describe('Datepicker', () => {
151
151
  expect(+_month - 1).eql(month);
152
152
  });
153
153
 
154
- it('week', async () => {
155
- const [instance, element] = mount(YearMonthDemo);
156
- const inputs = element.querySelectorAll<HTMLElement>('.k-input');
157
- const weekInput = inputs[2];
154
+ // it('week', async () => {
155
+ // const [instance, element] = mount(YearMonthDemo);
156
+ // const inputs = element.querySelectorAll<HTMLElement>('.k-input');
157
+ // const weekInput = inputs[2];
158
158
 
159
- weekInput.click();
160
- await wait();
159
+ // weekInput.click();
160
+ // await wait();
161
161
 
162
- const content = getElement('.k-datepicker-content')!;
163
- const weekItem = content.querySelector('.week-row:nth-child(1) .k-week-number') as HTMLElement;
164
- weekItem.click();
162
+ // const content = getElement('.k-datepicker-content')!;
163
+ // const weekItem = content.querySelector('.week-row:nth-child(1) .k-week-number') as HTMLElement;
164
+ // weekItem.click();
165
165
 
166
- expect(instance.get<string>('week')).to.match(/^\d{4}-\d+周$/)
167
- });
166
+ // expect(instance.get<string>('week')).to.match(/^\d{4}-\d+周$/)
167
+ // });
168
168
 
169
- it('quarter', async () => {
170
- const [instance, element] = mount(YearMonthDemo);
171
- const inputs = element.querySelectorAll<HTMLElement>('.k-input');
172
- const QuarterInput = inputs[3];
169
+ // it('quarter', async () => {
170
+ // const [instance, element] = mount(YearMonthDemo);
171
+ // const inputs = element.querySelectorAll<HTMLElement>('.k-input');
172
+ // const QuarterInput = inputs[3];
173
173
 
174
- QuarterInput.click();
175
- await wait();
176
- const content = getElement('.k-datepicker-content')!;
174
+ // QuarterInput.click();
175
+ // await wait();
176
+ // const content = getElement('.k-datepicker-content')!;
177
177
 
178
- // 选择第一个季度
179
- const quarterItem = content.querySelector('.k-calendar-item:nth-child(1)') as HTMLElement;
180
- quarterItem.click();
178
+ // // 选择第一个季度
179
+ // const quarterItem = content.querySelector('.k-calendar-item:nth-child(1)') as HTMLElement;
180
+ // quarterItem.click();
181
181
 
182
- // 验证输入框的值是否包含Q1
183
- expect(instance.get<string>('quarter')).to.include('Q1')
184
- });
182
+ // // 验证输入框的值是否包含Q1
183
+ // expect(instance.get<string>('quarter')).to.include('Q1')
184
+ // });
185
185
 
186
186
  });
187
187
 
@@ -1120,6 +1120,33 @@ describe('Datepicker', () => {
1120
1120
  await wait();
1121
1121
  expect(fn.callCount).to.eql(4);
1122
1122
  });
1123
+
1124
+ it('should trigger change event once', async () => {
1125
+ const change = sinon.spy(() => console.log('change'));
1126
+ class Demo extends Component<{value: string}> {
1127
+ static template = `
1128
+ const {Datepicker} = this;
1129
+ <Datepicker range ev-$change:value={this.onChange} v-model="value" clearable />
1130
+ `;
1131
+ private Datepicker = Datepicker;
1132
+
1133
+ onChange() {
1134
+ change();
1135
+ }
1136
+ }
1137
+ const [instance, element] = mount(Demo);
1138
+ const input = element.querySelector<HTMLInputElement>('.k-input-inner')!;
1139
+
1140
+ input.click();
1141
+ await wait();
1142
+ const calendar = getElement('.k-datepicker-content')!;
1143
+ const [day1, day2] = calendar.querySelectorAll<HTMLElement>('.k-calendar-item:not(.k-exceed)');
1144
+ day1.click();
1145
+ await wait();
1146
+ day2.click();
1147
+ await wait();
1148
+ expect(change.callCount).to.eql(1);
1149
+ });
1123
1150
  });
1124
1151
 
1125
1152
  it('should disable some time pickers', async () => {
@@ -214,8 +214,11 @@ export function useValueBase(
214
214
  }
215
215
 
216
216
  const valueStr = convertToValueString(_value);
217
- instance.set('value', valueStr);
218
- instance.resetKeywords();
217
+ // only trigger change event once
218
+ if (!isEqualArray(valueStr, instance.get('value'))) {
219
+ instance.set('value', valueStr);
220
+ instance.resetKeywords();
221
+ }
219
222
  }
220
223
 
221
224
  // TODO
@@ -0,0 +1,25 @@
1
+ import {Component} from 'intact';
2
+ import type {DropdownItem} from './item';
3
+
4
+ export interface ItemEvents {
5
+ onFocusin: () => void;
6
+ onFocusout: () => void;
7
+ onShowMenu: () => void;
8
+ onHideMenu: () => void;
9
+ onSelect: () => void;
10
+ }
11
+
12
+ export enum Direction {
13
+ Up,
14
+ Down
15
+ }
16
+
17
+ export type MenuKeyboardMethods = {
18
+ reset: () => void;
19
+ focus: (item: DropdownItem) => void;
20
+ }
21
+
22
+ export type ItemComponent = Component<{disabled: boolean}>
23
+
24
+ export const ITEM_EVENTS = 'ItemEvents';
25
+ export const MENU_KEYBOARD = 'MenuKeyboard';
@@ -1,10 +1,9 @@
1
1
  import {Component, TypeDefs, inject, VNodeComponentClass} from 'intact';
2
2
  import template from './item.vdt';
3
3
  import {bind} from '../utils';
4
- import {useItemKeyboard, MenuKeyboardMethods} from './useKeyboard';
4
+ import {useItemKeyboard} from './useItemKeyboard';
5
5
  import {Dropdown, DROPDOWN} from './dropdown';
6
6
  import {type DropdownMenu, DROPDOWN_MENU} from './menu';
7
- import {IgnoreClickEvent} from '../../hooks/useDocumentClick';
8
7
  import { Dropdown as ExportDropdown, DropdownMenu as ExportDropdownMenu } from '.';
9
8
  import { useConfigContext } from '../config';
10
9
  import type { Tooltip } from '../tooltip/tooltip';
@@ -3,7 +3,7 @@ import template from './menu.vdt';
3
3
  import {bind} from '../utils';
4
4
  import {Dropdown, DROPDOWN} from './dropdown';
5
5
  import {useTransition} from './useTransition';
6
- import {useMenuKeyboard} from './useKeyboard';
6
+ import {useMenuKeyboard} from './useMenuKeyboard';
7
7
  import {useMouseOutsidable} from '../../hooks/useMouseOutsidable';
8
8
  import {FeedbackCallback} from './usePosition';
9
9
  import { useConfigContext } from '../config';
@@ -0,0 +1,38 @@
1
+ import {useInstance, inject} from 'intact';
2
+ import {useRecordItem} from '../../hooks/useRecordComponent';
3
+ import {useState} from '../../hooks/useState';
4
+ import type {DropdownItem} from './item';
5
+ import { ItemEvents, MENU_KEYBOARD, MenuKeyboardMethods, ITEM_EVENTS } from './constants';
6
+
7
+ export function useItemKeyboard(itemEvents: Omit<ItemEvents, 'onFocusin' | 'onFocusout'>) {
8
+ const isFocus = useState(false);
9
+ const keyboard = inject<MenuKeyboardMethods>(MENU_KEYBOARD)!;
10
+ const instance = useInstance() as DropdownItem;
11
+
12
+ useRecordItem<DropdownItem, ItemEvents>(ITEM_EVENTS, instance, {
13
+ ...itemEvents,
14
+ onFocusin() {
15
+ isFocus.set(true);
16
+ },
17
+ onFocusout() {
18
+ isFocus.set(false);
19
+ },
20
+ });
21
+
22
+ return {
23
+ onMouseEnter(e: MouseEvent) {
24
+ instance.trigger('mouseenter', e);
25
+ if (instance.get('disabled')) return;
26
+ keyboard.focus(instance);
27
+ },
28
+
29
+ onMouseLeave(e: MouseEvent) {
30
+ instance.trigger('mouseleave', e);
31
+ keyboard.reset();
32
+ // If it is a virtual item, it needs to be reset manually because the DOM is reused.
33
+ isFocus.set(false);
34
+ },
35
+
36
+ isFocus,
37
+ }
38
+ }
@@ -5,47 +5,21 @@ import {
5
5
  useInstance,
6
6
  findDomFromVNode,
7
7
  provide,
8
- inject,
9
8
  Component,
10
- Children,
11
- VNodeComponentClass,
12
9
  isComponentClass,
13
10
  isComponentFunction,
14
11
  hasVNodeChildren,
15
12
  hasMultipleChildren,
16
13
  VNode,
17
14
  } from 'intact';
18
- import {useRecordParent, useRecordItem} from '../../hooks/useRecordComponent';
15
+ import {useRecordParent} from '../../hooks/useRecordComponent';
19
16
  import {useKeyboard} from '../../hooks/useKeyboard';
20
- import {useState} from '../../hooks/useState';
21
- import {eachChildren, isComponentVNode} from '../utils';
17
+ import {isComponentVNode} from '../utils';
22
18
  import {DropdownItem} from './item';
23
19
  // can not import DropdownMenu from index.ts, otherwise it will cause circle reference
24
20
  // import {DropdownMenu} from './';
25
21
  import {DropdownMenu} from './menu';
26
-
27
- interface ItemEvents {
28
- onFocusin: () => void;
29
- onFocusout: () => void;
30
- onShowMenu: () => void;
31
- onHideMenu: () => void;
32
- onSelect: () => void;
33
- }
34
-
35
- export enum Direction {
36
- Up,
37
- Down
38
- }
39
-
40
- export type MenuKeyboardMethods = {
41
- reset: () => void;
42
- focus: (item: DropdownItem) => void;
43
- }
44
-
45
- type ItemComponent = Component<{disabled: boolean}>
46
-
47
- const ITEM_EVENTS = 'ItemEvents';
48
- const MENU_KEYBOARD = 'MenuKeyboard';
22
+ import { ITEM_EVENTS, ItemEvents, Direction, MenuKeyboardMethods, MENU_KEYBOARD } from './constants';
49
23
 
50
24
  export function useMenuKeyboard() {
51
25
  const items: DropdownItem[] = [];
@@ -178,39 +152,6 @@ export function useMenuKeyboard() {
178
152
  ] as const;
179
153
  }
180
154
 
181
- export function useItemKeyboard(itemEvents: Omit<ItemEvents, 'onFocusin' | 'onFocusout'>) {
182
- const isFocus = useState(false);
183
- const keyboard = inject<MenuKeyboardMethods>(MENU_KEYBOARD)!;
184
- const instance = useInstance() as DropdownItem;
185
-
186
- useRecordItem<DropdownItem, ItemEvents>(ITEM_EVENTS, instance, {
187
- ...itemEvents,
188
- onFocusin() {
189
- isFocus.set(true);
190
- },
191
- onFocusout() {
192
- isFocus.set(false);
193
- },
194
- });
195
-
196
- return {
197
- onMouseEnter(e: MouseEvent) {
198
- instance.trigger('mouseenter', e);
199
- if (instance.get('disabled')) return;
200
- keyboard.focus(instance);
201
- },
202
-
203
- onMouseLeave(e: MouseEvent) {
204
- instance.trigger('mouseleave', e);
205
- keyboard.reset();
206
- // If it is a virtual item, it needs to be reset manually because the DOM is reused.
207
- isFocus.set(false);
208
- },
209
-
210
- isFocus,
211
- }
212
- }
213
-
214
155
  function fixIndex(index: number, max: number) {
215
156
  if (index > max) {
216
157
  index = 0;
@@ -71,6 +71,10 @@ export class Form extends Component<FormProps, FormEvents> {
71
71
  });
72
72
  }
73
73
 
74
+ public getAllInvalidFormItems() {
75
+ return this.items.filter(item => !item.isValid());
76
+ }
77
+
74
78
  public submit(e: Event) {
75
79
  this.validate().then(valid => {
76
80
  if (valid) {
@@ -63,7 +63,8 @@ export declare type ClassName = string | ((value: any, param: any) => string)
63
63
  | --- | --- | --- | --- |
64
64
  | validate | 验证表单所有规则 | - | `Promise<boolean>`: `.then(valid => {})`,`valid`为`true`验证成功,否则失败 |
65
65
  | reset | 重置表单验证状态 | - | `undefined` |
66
- | getFirstInvalidFormItem | 获取第一条出错的`FormItem` | - | `FormItem` |
66
+ | getFirstInvalidFormItem | 获取第一条校验失败的`FormItem` | - | `FormItem` |
67
+ | getAllInvalidFormItems | 获取所有校验失败的`FormItem` | - | `FormItem[]` |
67
68
 
68
69
  # 静态方法
69
70
 
@@ -33,6 +33,8 @@ describe('Form', () => {
33
33
  expect(element.innerHTML).to.matchSnapshot();
34
34
  const item = form.getFirstInvalidFormItem()!;
35
35
  expect(item.get('label')).to.eql('Input');
36
+ const items = form.getAllInvalidFormItems();
37
+ expect(items.length).to.eql(10);
36
38
 
37
39
  instance.reset();
38
40
  await wait();
@@ -27,7 +27,13 @@ import {Menu, MenuItem, Switch, Icon} from 'kpc';
27
27
  </MenuItem>
28
28
  </Menu>
29
29
  </MenuItem>
30
- <MenuItem key="4"><Icon class="ion-gear-b" />menu 4</MenuItem>
30
+ <MenuItem key="4">
31
+ <Icon class="ion-gear-b" />menu 4
32
+ <Menu>
33
+ <MenuItem key="4-1">sub menu 1</MenuItem>
34
+ <MenuItem key="4-2">sub menu 2</MenuItem>
35
+ </Menu>
36
+ </MenuItem>
31
37
  </Menu>
32
38
  <br /><br />
33
39
  <Switch
@@ -3,6 +3,7 @@ import BasicDemo from '~/components/menu/demos/basic';
3
3
  import CollapseDemo from '~/components/menu/demos/collapse';
4
4
  import AccordionDemo from '~/components/menu/demos/accordion';
5
5
  import CollapseArrowDemo from '~/components/menu/demos/showCollapseArrow';
6
+ import HorizontalDemo from '~/components/menu/demos/horizontal';
6
7
  import {mount, unmount, dispatchEvent, getElement, wait} from '../../test/utils';
7
8
  import {Menu, MenuItem} from './';
8
9
 
@@ -190,4 +191,22 @@ describe('Menu', () => {
190
191
  expect(element.outerHTML).to.matchSnapshot();
191
192
  expect(getElement('.k-menu-arrow-box')).to.be.undefined;
192
193
  });
194
+
195
+ it('detecting pop-up position during rapid mouse hover over menus', async () => {
196
+ const [instance, element] = mount(HorizontalDemo);
197
+
198
+ const [, , menu3, menu4] = element.querySelectorAll<HTMLElement>('.k-menu-item-title');
199
+ dispatchEvent(menu3, 'mouseenter');
200
+ await wait(500);
201
+ const dropdownmenu1 = getElement('.k-dropdown-menu')!;
202
+ const top1 = dropdownmenu1.getBoundingClientRect().top;
203
+
204
+ dispatchEvent(menu3, 'mouseleave');
205
+ dispatchEvent(menu4, 'mouseenter');
206
+ await wait(1000);
207
+ const dropdownmenu2 = getElement('.k-dropdown-menu')!;
208
+ const top2 = dropdownmenu2.getBoundingClientRect().top;
209
+
210
+ expect(top1).to.eql(top2);
211
+ });
193
212
  });
@@ -18,7 +18,7 @@ const defaults = {
18
18
  item: {
19
19
  height: '40px',
20
20
  padding: '0 12px',
21
- bodyPadding: '0 4px',
21
+ bodyPadding: '4px',
22
22
  color: '#aeaeb9',
23
23
  hoverColor: '#fff',
24
24
  disabledColor: '#53535a',
@@ -292,6 +292,7 @@ export const makeMenuStyles = cache(function makeMenuStyles(k: string) {
292
292
  &.${k}-dropdown-menu {
293
293
  width: fit-content;
294
294
  min-width: ${menu.dropdown.minWidth};
295
+ position: absolute;
295
296
  .${k}-menu-item-arrow {
296
297
  transform: rotate(-90deg)
297
298
  }
@@ -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
 
@@ -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
  }
@@ -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;
@@ -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
  }