@king-design/intact 2.0.17-beta.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/cascader/index.md +18 -0
- package/components/cascader/index.spec.ts +56 -0
- package/components/cascader/index.ts +35 -12
- package/components/cascader/index.vdt +9 -8
- package/components/cascader/useFields.ts +22 -0
- package/components/cascader/useFilterable.ts +23 -8
- package/components/cascader/useLabel.ts +7 -4
- package/components/cascader/useLoad.ts +4 -2
- package/components/code/demos/basic.md +1 -1
- package/components/colorpicker/index.md +16 -0
- package/components/colorpicker/index.ts +4 -0
- package/components/colorpicker/index.vdt +3 -2
- package/components/datepicker/index.md +11 -0
- package/components/dialog/index.spec.ts +2 -2
- package/components/dropdown/dropdown.ts +34 -71
- package/components/dropdown/index.spec.ts +53 -4
- package/components/dropdown/item.ts +18 -7
- package/components/dropdown/menu.ts +3 -3
- package/components/dropdown/usePosition.ts +12 -1
- package/components/editable/index.ts +17 -3
- package/components/editable/index.vdt +1 -0
- package/components/input/demos/autoRows.md +44 -0
- package/components/input/demos/password.md +12 -0
- package/components/input/demos/textarea.md +2 -2
- package/components/input/index.md +1 -0
- package/components/input/index.spec.ts +97 -1
- package/components/input/index.ts +17 -3
- package/components/input/index.vdt +29 -6
- package/components/input/styles.ts +18 -1
- package/components/input/useAutoRows.ts +65 -0
- package/components/input/useAutoWidth.ts +12 -3
- package/components/input/useShowPassword.ts +27 -0
- package/components/menu/demos/collapse.md +1 -1
- package/components/menu/index.spec.ts +9 -1
- package/components/menu/item.ts +7 -0
- package/components/pagination/index.spec.ts +24 -1
- package/components/pagination/index.ts +2 -1
- package/components/portal.ts +4 -4
- package/components/position.ts +5 -1
- package/components/select/base.ts +3 -1
- package/components/select/base.vdt +2 -0
- package/components/select/index.md +11 -1
- package/components/table/cell.ts +4 -5
- package/components/table/demos/hideHeader.md +33 -0
- package/components/table/demos/pagination.md +53 -0
- package/components/table/index.md +22 -0
- package/components/table/index.spec.ts +73 -1
- package/components/table/row.ts +3 -3
- package/components/table/styles.ts +5 -0
- package/components/table/table.ts +29 -4
- package/components/table/table.vdt +21 -3
- package/components/table/useChecked.ts +21 -6
- package/components/table/useDisableRow.ts +3 -2
- package/components/table/useDraggable.ts +11 -8
- package/components/table/useGroup.ts +2 -0
- package/components/table/useMerge.ts +6 -3
- package/components/table/usePagination.ts +71 -0
- package/components/table/useRestRowStatus.ts +4 -1
- package/components/table/useTree.ts +4 -3
- package/components/timepicker/index.md +11 -0
- package/components/tooltip/content.ts +15 -1
- package/components/tooltip/content.vdt +6 -1
- package/components/tooltip/demos/trigger.md +1 -1
- package/components/tooltip/index.md +1 -1
- package/components/tooltip/index.spec.ts +65 -6
- package/components/tooltip/styles.ts +1 -1
- package/components/tooltip/tooltip.ts +8 -0
- package/components/treeSelect/index.md +9 -0
- package/components/virtual.ts +98 -0
- package/es/components/cascader/index.d.ts +22 -11
- package/es/components/cascader/index.js +9 -12
- package/es/components/cascader/index.spec.js +81 -0
- package/es/components/cascader/index.vdt.js +10 -8
- package/es/components/cascader/useFields.d.ts +2 -0
- package/es/components/cascader/useFields.js +18 -0
- package/es/components/cascader/useFilterable.d.ts +2 -1
- package/es/components/cascader/useFilterable.js +17 -6
- package/es/components/cascader/useLabel.d.ts +2 -1
- package/es/components/cascader/useLabel.js +4 -4
- package/es/components/cascader/useLoad.d.ts +2 -1
- package/es/components/cascader/useLoad.js +9 -7
- package/es/components/colorpicker/index.d.ts +2 -0
- package/es/components/colorpicker/index.js +7 -2
- package/es/components/colorpicker/index.vdt.js +3 -6
- package/es/components/dialog/index.spec.js +2 -2
- package/es/components/dropdown/dropdown.d.ts +6 -5
- package/es/components/dropdown/dropdown.js +40 -69
- package/es/components/dropdown/index.spec.js +96 -17
- package/es/components/dropdown/item.d.ts +1 -1
- package/es/components/dropdown/item.js +19 -7
- package/es/components/dropdown/usePosition.js +11 -2
- package/es/components/editable/index.d.ts +1 -0
- package/es/components/editable/index.js +20 -6
- package/es/components/editable/index.vdt.js +2 -1
- package/es/components/input/index.d.ts +10 -2
- package/es/components/input/index.js +10 -3
- package/es/components/input/index.spec.js +169 -1
- package/es/components/input/index.vdt.js +26 -7
- package/es/components/input/styles.js +8 -3
- package/es/components/input/useAutoRows.d.ts +2 -0
- package/es/components/input/useAutoRows.js +79 -0
- package/es/components/input/useAutoWidth.js +13 -3
- package/es/components/input/useShowPassword.d.ts +7 -0
- package/es/components/input/useShowPassword.js +31 -0
- package/es/components/menu/index.spec.js +26 -15
- package/es/components/menu/item.d.ts +2 -0
- package/es/components/menu/item.js +5 -0
- package/es/components/pagination/index.js +2 -1
- package/es/components/pagination/index.spec.js +51 -4
- package/es/components/portal.d.ts +6 -2
- package/es/components/portal.js +4 -3
- package/es/components/position.js +2 -1
- package/es/components/select/base.d.ts +2 -1
- package/es/components/select/base.js +3 -1
- package/es/components/select/base.vdt.js +3 -1
- package/es/components/table/cell.js +1 -6
- package/es/components/table/index.spec.js +130 -19
- package/es/components/table/row.d.ts +1 -1
- package/es/components/table/row.js +2 -1
- package/es/components/table/styles.js +1 -1
- package/es/components/table/table.d.ts +15 -0
- package/es/components/table/table.js +16 -7
- package/es/components/table/table.vdt.js +20 -6
- package/es/components/table/useChecked.d.ts +3 -2
- package/es/components/table/useChecked.js +23 -12
- package/es/components/table/useDisableRow.d.ts +2 -1
- package/es/components/table/useDisableRow.js +4 -4
- package/es/components/table/useDraggable.d.ts +3 -2
- package/es/components/table/useDraggable.js +11 -8
- package/es/components/table/useGroup.js +3 -0
- package/es/components/table/useMerge.d.ts +2 -1
- package/es/components/table/useMerge.js +5 -4
- package/es/components/table/usePagination.d.ts +8 -0
- package/es/components/table/usePagination.js +81 -0
- package/es/components/table/useTree.d.ts +2 -1
- package/es/components/table/useTree.js +3 -4
- package/es/components/tooltip/content.d.ts +1 -0
- package/es/components/tooltip/content.js +18 -1
- package/es/components/tooltip/content.vdt.js +3 -1
- package/es/components/tooltip/index.spec.js +117 -10
- package/es/components/tooltip/styles.d.ts +22 -0
- package/es/components/tooltip/styles.js +1 -1
- package/es/components/tooltip/tooltip.d.ts +1 -0
- package/es/components/tooltip/tooltip.js +11 -0
- package/es/components/virtual.d.ts +8 -0
- package/es/components/virtual.js +126 -0
- package/es/index.d.ts +3 -3
- package/es/index.js +3 -3
- package/es/packages/kpc-react/__tests__/components/cascader.spec.d.ts +1 -0
- package/es/packages/kpc-react/__tests__/components/cascader.spec.js +79 -0
- package/es/site/data/components/input/demos/autoRows/index.d.ts +9 -0
- package/es/site/data/components/input/demos/autoRows/index.js +24 -0
- package/es/site/data/components/input/demos/autoRows/react.d.ts +8 -0
- package/es/site/data/components/input/demos/autoRows/react.js +62 -0
- package/es/site/data/components/input/demos/password/index.d.ts +5 -0
- package/es/site/data/components/input/demos/password/index.js +17 -0
- package/es/site/data/components/input/demos/password/react.d.ts +5 -0
- package/es/site/data/components/input/demos/password/react.js +41 -0
- package/es/site/data/components/input/demos/textarea/react.js +4 -2
- package/es/site/data/components/menu/demos/collapse/index.js +1 -1
- package/es/site/data/components/menu/demos/collapse/react.js +1 -1
- package/es/site/data/components/table/demos/hideHeader/index.d.ts +12 -0
- package/es/site/data/components/table/demos/hideHeader/index.js +30 -0
- package/es/site/data/components/table/demos/hideHeader/react.d.ts +11 -0
- package/es/site/data/components/table/demos/hideHeader/react.js +60 -0
- package/es/site/data/components/table/demos/pagination/index.d.ts +12 -0
- package/es/site/data/components/table/demos/pagination/index.js +35 -0
- package/es/site/data/components/table/demos/pagination/react.d.ts +16 -0
- package/es/site/data/components/table/demos/pagination/react.js +65 -0
- package/es/styles/fonts/ionicons.js +1 -1
- package/index.ts +3 -3
- package/package.json +5 -4
- package/styles/fonts/ionicons.ts +0 -1
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
createVNode,
|
|
12
12
|
nextTick,
|
|
13
13
|
} from 'intact';
|
|
14
|
-
import {bind, isTextChildren} from '../utils';
|
|
14
|
+
import {bind, isTextChildren, getRestProps} from '../utils';
|
|
15
15
|
import {EMPTY_OBJ, isFunction, noop} from 'intact-shared';
|
|
16
16
|
import {Options, position, Feedback} from '../position';
|
|
17
17
|
import {cx} from '@emotion/css';
|
|
@@ -21,6 +21,7 @@ import {Portal, PortalProps} from '../portal';
|
|
|
21
21
|
import {useShowHideEvents} from '../../hooks/useShowHideEvents';
|
|
22
22
|
import {usePosition, FeedbackCallback} from './usePosition';
|
|
23
23
|
import type {Events} from '../types';
|
|
24
|
+
import { Virtual } from '../virtual';
|
|
24
25
|
|
|
25
26
|
export type Position = Options
|
|
26
27
|
export type PositionShorthand = 'left' | 'bottom' | 'right' | 'top'
|
|
@@ -35,6 +36,7 @@ export interface DropdownProps {
|
|
|
35
36
|
disabled?: boolean
|
|
36
37
|
value?: boolean
|
|
37
38
|
position?: Position | 'left' | 'bottom' | 'right' | 'top'
|
|
39
|
+
collison?: Position['collision']
|
|
38
40
|
of?: 'self' | 'parent' | Event
|
|
39
41
|
container?: PortalProps['container']
|
|
40
42
|
}
|
|
@@ -45,6 +47,8 @@ export interface DropdownEvents {
|
|
|
45
47
|
hide: []
|
|
46
48
|
mouseenter: [MouseEvent]
|
|
47
49
|
mouseleave: [MouseEvent]
|
|
50
|
+
click: [MouseEvent]
|
|
51
|
+
contextmenu: [MouseEvent]
|
|
48
52
|
positioned: [Feedback]
|
|
49
53
|
}
|
|
50
54
|
|
|
@@ -58,11 +62,11 @@ const typeDefs: Required<TypeDefs<DropdownProps>> = {
|
|
|
58
62
|
// Event is undefined in NodeJs
|
|
59
63
|
of: ['self', 'parent', typeof Event === 'undefined' ? undefined : Event],
|
|
60
64
|
container: [String, Function],
|
|
65
|
+
collison: ['none', 'fit', 'flip', 'flipfit', Array],
|
|
61
66
|
};
|
|
62
67
|
|
|
63
68
|
const defaults = (): Partial<DropdownProps> => ({
|
|
64
69
|
trigger: 'hover',
|
|
65
|
-
position: {},
|
|
66
70
|
of: 'self',
|
|
67
71
|
});
|
|
68
72
|
|
|
@@ -72,6 +76,8 @@ const events: Events<DropdownEvents> = {
|
|
|
72
76
|
hide: true,
|
|
73
77
|
mouseenter: true,
|
|
74
78
|
mouseleave: true,
|
|
79
|
+
click: true,
|
|
80
|
+
contextmenu: true,
|
|
75
81
|
positioned: true,
|
|
76
82
|
};
|
|
77
83
|
|
|
@@ -105,28 +111,18 @@ export class Dropdown<
|
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
const [trigger, menu] = children as DropdownChildren;
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const clonedTrigger = isTextChildren(trigger) ?
|
|
112
|
-
createVNode('span', null, trigger) :
|
|
113
|
-
directClone(trigger);
|
|
114
|
-
const triggerProps = this.triggerProps = this.normalizeTriggerProps(trigger.props || EMPTY_OBJ);
|
|
115
|
-
// add a className for opening status
|
|
116
|
-
let className = trigger.className || triggerProps.className;
|
|
114
|
+
const props = this.initEventCallbacks();
|
|
115
|
+
let {className, value, container} = this.get();
|
|
117
116
|
className = cx({
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
'k-dropdown-open': value,
|
|
118
|
+
[className!]: !!className,
|
|
120
119
|
});
|
|
121
|
-
|
|
122
|
-
clonedTrigger.props = {...triggerProps, ...props, className};
|
|
123
|
-
clonedTrigger.className = className;
|
|
124
|
-
|
|
120
|
+
|
|
125
121
|
this.menuVNode = menu;
|
|
126
122
|
|
|
127
123
|
return [
|
|
128
|
-
|
|
129
|
-
h(Portal, {children: menu, container
|
|
124
|
+
h(Virtual, {...props, ...getRestProps(this), className}, trigger),
|
|
125
|
+
h(Portal, {children: menu, container})
|
|
130
126
|
];
|
|
131
127
|
};
|
|
132
128
|
|
|
@@ -136,8 +132,7 @@ export class Dropdown<
|
|
|
136
132
|
public showedDropdown: Dropdown | null = null;
|
|
137
133
|
public positionHook = usePosition();
|
|
138
134
|
|
|
139
|
-
|
|
140
|
-
private triggerProps: any = null;
|
|
135
|
+
protected timer: number | undefined = undefined;
|
|
141
136
|
|
|
142
137
|
init() {
|
|
143
138
|
provide(DROPDOWN, this);
|
|
@@ -168,6 +163,12 @@ export class Dropdown<
|
|
|
168
163
|
clearTimeout(this.timer);
|
|
169
164
|
this.set('value', true);
|
|
170
165
|
|
|
166
|
+
// should show parent dropdown
|
|
167
|
+
const parentDropdown = this.dropdown;
|
|
168
|
+
if (parentDropdown) {
|
|
169
|
+
parentDropdown.show();
|
|
170
|
+
}
|
|
171
|
+
|
|
171
172
|
if (shouldFocus) {
|
|
172
173
|
nextTick(() => {
|
|
173
174
|
this.focusFirst();
|
|
@@ -179,9 +180,15 @@ export class Dropdown<
|
|
|
179
180
|
if (this.get('disabled')) return;
|
|
180
181
|
if (!this.get('value')) return;
|
|
181
182
|
|
|
183
|
+
const showedDropdown = this.showedDropdown;
|
|
184
|
+
if (showedDropdown) {
|
|
185
|
+
showedDropdown.hide(immediately);
|
|
186
|
+
}
|
|
187
|
+
|
|
182
188
|
if (immediately) {
|
|
183
189
|
this.set('value', false);
|
|
184
190
|
} else {
|
|
191
|
+
clearTimeout(this.timer);
|
|
185
192
|
this.timer = window.setTimeout(() => {
|
|
186
193
|
this.set('value', false);
|
|
187
194
|
}, 200);
|
|
@@ -199,29 +206,27 @@ export class Dropdown<
|
|
|
199
206
|
|
|
200
207
|
@bind
|
|
201
208
|
private onEnter(e: MouseEvent) {
|
|
202
|
-
this.callOriginalCallback(e.type === 'click' ? 'ev-click' : 'ev-mouseenter', e);
|
|
203
|
-
|
|
204
209
|
this.show();
|
|
210
|
+
this.trigger(e.type as 'mouseenter', e);
|
|
205
211
|
}
|
|
206
212
|
|
|
207
213
|
@bind
|
|
208
214
|
private onContextMenu(e: MouseEvent) {
|
|
209
|
-
this.callOriginalCallback('ev-contextmenu', e);
|
|
210
|
-
|
|
211
215
|
e.preventDefault();
|
|
212
216
|
this.set('of', e);
|
|
213
217
|
this.show();
|
|
218
|
+
this.trigger('contextmenu', e);
|
|
214
219
|
}
|
|
215
220
|
|
|
216
221
|
@bind
|
|
217
222
|
private onLeave(e: MouseEvent) {
|
|
218
|
-
this.callOriginalCallback('ev-mouseleave', e);
|
|
219
|
-
|
|
220
223
|
this.hide();
|
|
224
|
+
this.trigger(e.type as 'mouseleave', e);
|
|
221
225
|
}
|
|
222
226
|
|
|
223
|
-
private initEventCallbacks(
|
|
224
|
-
const
|
|
227
|
+
private initEventCallbacks() {
|
|
228
|
+
const trigger = this.get('trigger');
|
|
229
|
+
const props: Record<string, Function | string> = {};
|
|
225
230
|
|
|
226
231
|
switch (trigger) {
|
|
227
232
|
case 'focus':
|
|
@@ -242,48 +247,6 @@ export class Dropdown<
|
|
|
242
247
|
|
|
243
248
|
return props;
|
|
244
249
|
}
|
|
245
|
-
|
|
246
|
-
private callOriginalCallback(name: string, e: MouseEvent) {
|
|
247
|
-
const callback = this.triggerProps[name];
|
|
248
|
-
const callbackOnDropdown = this.get<Function>(name);
|
|
249
|
-
if (isFunction(callback)) callback(e);
|
|
250
|
-
if (isFunction(callbackOnDropdown)) callbackOnDropdown(e);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
private normalizeTriggerProps(props: any) {
|
|
254
|
-
// if use kpc in react or vue, normalize props by Wrapper.props.vnode;
|
|
255
|
-
const vnode = props.vnode;
|
|
256
|
-
if (!vnode) return props;
|
|
257
|
-
|
|
258
|
-
// maybe we render the intact component in react slot property, in this case
|
|
259
|
-
// the $isReact is false. so use the vnode $$typeof field as gauge
|
|
260
|
-
if (vnode.$$typeof || (this as any).$isVueNext) {
|
|
261
|
-
const _props = vnode.props;
|
|
262
|
-
if (!_props) return props;
|
|
263
|
-
|
|
264
|
-
return {
|
|
265
|
-
vnode,
|
|
266
|
-
'ev-click': _props.onClick,
|
|
267
|
-
'ev-mouseenter': _props.onMouseEnter,
|
|
268
|
-
'ev-mouseleave': _props.onMouseLeave,
|
|
269
|
-
'ev-contextmenu': _props.onContextMenu,
|
|
270
|
-
className: _props.className || _props.class /* vue-next */,
|
|
271
|
-
};
|
|
272
|
-
} else if ((this as any).$isVue) {
|
|
273
|
-
const data = vnode.data;
|
|
274
|
-
const on = data && data.on || EMPTY_OBJ;
|
|
275
|
-
const ret: Record<string, any> = {vnode};
|
|
276
|
-
['click', 'mouseenter', 'mouseleave', 'contextmenu'].forEach(event => {
|
|
277
|
-
const method = on[event];
|
|
278
|
-
if (method) {
|
|
279
|
-
ret[`ev-${event}`] = method;
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
return ret;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return props;
|
|
286
|
-
}
|
|
287
250
|
}
|
|
288
251
|
|
|
289
252
|
function useDocumentClickForDropdown(dropdown: Dropdown) {
|
|
@@ -4,6 +4,7 @@ import {Dropdown, DropdownMenu, DropdownItem} from '../dropdown';
|
|
|
4
4
|
import BasicDemo from '~/components/dropdown/demos/basic';
|
|
5
5
|
import NestedDemo from '~/components/dropdown/demos/nested';
|
|
6
6
|
import ContextMenuDemo from '~/components/dropdown/demos/contextmenu';
|
|
7
|
+
import TooltipDemo from '~/components/dropdown/demos/tooltip';
|
|
7
8
|
|
|
8
9
|
describe('Dropdown', () => {
|
|
9
10
|
afterEach((done) => {
|
|
@@ -72,7 +73,8 @@ describe('Dropdown', () => {
|
|
|
72
73
|
expect(dropdown.parentNode).to.exist;
|
|
73
74
|
});
|
|
74
75
|
|
|
75
|
-
it('nested dropdown', async ()
|
|
76
|
+
it('nested dropdown', async function() {
|
|
77
|
+
this.timeout(0);
|
|
76
78
|
const [instance, element] = mount(NestedDemo);
|
|
77
79
|
|
|
78
80
|
(element.firstElementChild as HTMLElement).click();
|
|
@@ -89,6 +91,20 @@ describe('Dropdown', () => {
|
|
|
89
91
|
await wait(500);
|
|
90
92
|
const hoverSubDropdown = getElement('.k-dropdown-menu')!;
|
|
91
93
|
expect(hoverSubDropdown.innerHTML).to.matchSnapshot();
|
|
94
|
+
|
|
95
|
+
const [hoverItem1] = hoverSubDropdown.querySelectorAll<HTMLElement>('.k-dropdown-item');
|
|
96
|
+
dispatchEvent(hoverItem, 'mouseleave');
|
|
97
|
+
dispatchEvent(hoverItem1, 'mouseenter');
|
|
98
|
+
await wait(500);
|
|
99
|
+
const hoverSubDropdown1 = getElement('.k-dropdown-menu')!;
|
|
100
|
+
expect(hoverSubDropdown1.textContent).to.eql('item 1item 2');
|
|
101
|
+
|
|
102
|
+
const [hoverItem2] = hoverSubDropdown1.querySelectorAll<HTMLElement>('.k-dropdown-item');
|
|
103
|
+
dispatchEvent(hoverItem1, 'mouseleave');
|
|
104
|
+
dispatchEvent(hoverItem2, 'mouseenter');
|
|
105
|
+
await wait(1000);
|
|
106
|
+
const hoverSubDropdown2 = getElement('.k-dropdown-menu')!;
|
|
107
|
+
expect(hoverSubDropdown2 === hoverSubDropdown1).to.be.true;
|
|
92
108
|
});
|
|
93
109
|
|
|
94
110
|
it('hide on click document', async () => {
|
|
@@ -281,13 +297,13 @@ describe('Dropdown', () => {
|
|
|
281
297
|
expect(parent.scrollTop).to.eql(item.offsetHeight * 2 - 40);
|
|
282
298
|
});
|
|
283
299
|
|
|
284
|
-
it('trigger
|
|
300
|
+
it('focus trigger type', async () => {
|
|
285
301
|
class Demo extends Component {
|
|
286
302
|
static template = `
|
|
287
303
|
const {Dropdown, DropdownMenu, DropdownItem} = this;
|
|
288
304
|
<div>
|
|
289
305
|
<Dropdown trigger="focus">
|
|
290
|
-
<input ref="trigger" />
|
|
306
|
+
<input ref="trigger" ev-focusin={this.onFocus} />
|
|
291
307
|
<DropdownMenu>
|
|
292
308
|
<DropdownItem>test1</DropdownItem>
|
|
293
309
|
<DropdownItem>test2</DropdownItem>
|
|
@@ -298,12 +314,14 @@ describe('Dropdown', () => {
|
|
|
298
314
|
private Dropdown = Dropdown;
|
|
299
315
|
private DropdownItem = DropdownItem;
|
|
300
316
|
private DropdownMenu = DropdownMenu;
|
|
317
|
+
public onFocus = sinon.spy((e: MouseEvent) => console.log(e));
|
|
301
318
|
}
|
|
302
319
|
const [instance] = mount(Demo);
|
|
303
320
|
|
|
304
321
|
dispatchEvent(instance.refs.trigger, 'focusin');
|
|
305
322
|
await wait(500);
|
|
306
323
|
expect(getElement('.k-dropdown-menu')).to.be.exist;
|
|
324
|
+
expect(instance.onFocus.callCount).to.eql(1);
|
|
307
325
|
|
|
308
326
|
// clicking anywhere should not hide menu
|
|
309
327
|
dispatchEvent(document, 'click');
|
|
@@ -314,4 +332,35 @@ describe('Dropdown', () => {
|
|
|
314
332
|
await wait(700);
|
|
315
333
|
expect(getElement('.k-dropdown-menu')).to.not.be.exist;
|
|
316
334
|
});
|
|
317
|
-
|
|
335
|
+
|
|
336
|
+
it('wrap by tooltip', async () => {
|
|
337
|
+
const [instance, element] = mount(TooltipDemo);
|
|
338
|
+
|
|
339
|
+
dispatchEvent(element.firstChild as HTMLElement, 'mouseenter');
|
|
340
|
+
await wait();
|
|
341
|
+
const dropdown = getElement('.k-dropdown-menu')!;
|
|
342
|
+
const [item1, item2, item3, item4] = dropdown.querySelectorAll('.k-dropdown-item');
|
|
343
|
+
|
|
344
|
+
dispatchEvent(item1, 'mouseenter');
|
|
345
|
+
await wait();
|
|
346
|
+
expect(getElement('.k-tooltip-content')!.textContent).to.eql('item 1')
|
|
347
|
+
|
|
348
|
+
dispatchEvent(item1, 'mouseleave');
|
|
349
|
+
dispatchEvent(item3, 'mouseenter');
|
|
350
|
+
await wait();
|
|
351
|
+
expect(getElement('.k-tooltip-content')!.textContent).to.eql('disabled')
|
|
352
|
+
|
|
353
|
+
dispatchEvent(item3, 'mouseleave');
|
|
354
|
+
dispatchEvent(item4, 'mouseenter');
|
|
355
|
+
await wait();
|
|
356
|
+
expect(getElement('.k-tooltip-content')!.textContent).to.eql('This is a nested Dropdown.');
|
|
357
|
+
|
|
358
|
+
dispatchEvent(item4, 'click');
|
|
359
|
+
await wait();
|
|
360
|
+
expect(getElement('.k-dropdown-menu')!.textContent).to.eql('item 1item 2');
|
|
361
|
+
|
|
362
|
+
dispatchEvent(item4, 'mouseleave');
|
|
363
|
+
await wait(800);
|
|
364
|
+
expect(getElement('.k-dropdown-menu')).to.not.be.exist;
|
|
365
|
+
});
|
|
366
|
+
});
|
|
@@ -5,6 +5,7 @@ import {useItemKeyboard, MenuKeyboardMethods} from './useKeyboard';
|
|
|
5
5
|
import {Dropdown, DROPDOWN} from './dropdown';
|
|
6
6
|
import {DropdownMenu, DROPDOWN_MENU} from './menu';
|
|
7
7
|
import {IgnoreClickEvent} from '../../hooks/useDocumentClick';
|
|
8
|
+
import { Dropdown as ExportDropdown, DropdownMenu as ExportDropdownMenu } from '.';
|
|
8
9
|
|
|
9
10
|
export interface DropdownItemProps {
|
|
10
11
|
disabled?: boolean
|
|
@@ -52,21 +53,31 @@ export class DropdownItem extends Component<DropdownItemProps, DropdownItemEvent
|
|
|
52
53
|
select() {
|
|
53
54
|
if (this.parentDropdown) return;
|
|
54
55
|
|
|
56
|
+
// trigger select event firstly for Cascader update values
|
|
57
|
+
this.trigger('select');
|
|
58
|
+
|
|
55
59
|
if (this.get('hideOnSelect')) {
|
|
56
60
|
// hide all dropdowns
|
|
57
61
|
let dropdown = this.dropdown;
|
|
58
62
|
do { dropdown!.hide(true); }
|
|
59
63
|
while (dropdown = dropdown!.dropdown);
|
|
60
64
|
}
|
|
61
|
-
|
|
62
|
-
this.trigger('select');
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
hasSubMenu() {
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
// wrapped by Dropdown rather than DropdownMenu
|
|
69
|
+
let parent = this.$senior;
|
|
70
|
+
while (parent) {
|
|
71
|
+
// Tooltip extends Dropdown, it's also a instance of Dropdown
|
|
72
|
+
// so use constructor to detect
|
|
73
|
+
// if (parent instanceof DropdownMenu) {
|
|
74
|
+
if (parent.constructor === ExportDropdownMenu) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (parent.constructor === ExportDropdown) {
|
|
78
|
+
return parent;
|
|
79
|
+
}
|
|
80
|
+
parent = parent.$senior;
|
|
70
81
|
}
|
|
71
82
|
}
|
|
72
83
|
|
|
@@ -104,4 +115,4 @@ function useKeyboardForDropdownItem(instance: DropdownItem) {
|
|
|
104
115
|
instance.select();
|
|
105
116
|
},
|
|
106
117
|
});
|
|
107
|
-
}
|
|
118
|
+
}
|
|
@@ -35,8 +35,8 @@ export class DropdownMenu<
|
|
|
35
35
|
@bind
|
|
36
36
|
protected onMouseEnter(e: MouseEvent) {
|
|
37
37
|
const dropdown = this.dropdown!;
|
|
38
|
-
dropdown
|
|
39
|
-
dropdown
|
|
38
|
+
dropdown.show();
|
|
39
|
+
dropdown.trigger('mouseenter', e);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
@bind
|
|
@@ -78,4 +78,4 @@ function useKeyboardForDropdownMenu(dropdown: Dropdown) {
|
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
return {lock};
|
|
81
|
-
}
|
|
81
|
+
}
|
|
@@ -2,6 +2,7 @@ import {useInstance, findDomFromVNode} from 'intact';
|
|
|
2
2
|
import type {Dropdown} from './';
|
|
3
3
|
import {Options, position, Feedback} from '../position';
|
|
4
4
|
import {noop} from 'intact-shared';
|
|
5
|
+
import {isObject} from 'intact-shared';
|
|
5
6
|
|
|
6
7
|
export type FeedbackCallback = (feedback: Feedback) => void;
|
|
7
8
|
|
|
@@ -16,7 +17,16 @@ export function usePosition() {
|
|
|
16
17
|
});
|
|
17
18
|
|
|
18
19
|
(['of', 'position'] as const).forEach(item => {
|
|
19
|
-
instance.watch(item, () => {
|
|
20
|
+
instance.watch(item, (newValue, oldValue) => {
|
|
21
|
+
// return if object is the same
|
|
22
|
+
if (
|
|
23
|
+
isObject(newValue) && isObject(oldValue) &&
|
|
24
|
+
// is not event object
|
|
25
|
+
!(newValue instanceof Event) &&
|
|
26
|
+
JSON.stringify(newValue) === JSON.stringify(oldValue)
|
|
27
|
+
) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
20
30
|
if (instance.get('value')) {
|
|
21
31
|
handle(noop);
|
|
22
32
|
}
|
|
@@ -48,6 +58,7 @@ export function usePosition() {
|
|
|
48
58
|
position(findDomFromVNode(instance.menuVNode!, true) as HTMLElement, {
|
|
49
59
|
my: 'left top+8',
|
|
50
60
|
at: 'left bottom',
|
|
61
|
+
collision: instance.get('collison'),
|
|
51
62
|
...pos,
|
|
52
63
|
of: ofElement,
|
|
53
64
|
using: _feedback => {
|
|
@@ -58,9 +58,23 @@ export class Editable<
|
|
|
58
58
|
@bind
|
|
59
59
|
private edit() {
|
|
60
60
|
this.set('editing', true);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Intact will update in nextTick, but Vue will call
|
|
63
|
+
* call updated method in nextTick of this nextTick
|
|
64
|
+
* so we should do it after two nextTicks
|
|
65
|
+
* https://github.com/ksc-fe/kpc/issues/847
|
|
66
|
+
*
|
|
67
|
+
* use binding this.select to Input $mounted event instead
|
|
68
|
+
*/
|
|
69
|
+
// nextTick(() => {
|
|
70
|
+
// nextTick(() => {
|
|
71
|
+
// this.inputRef.value!.select();
|
|
72
|
+
// });
|
|
73
|
+
// });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@bind select() {
|
|
77
|
+
this.inputRef.value!.select();
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
@bind
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 文本框自适应高度
|
|
3
|
+
order: 3.1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
当`textarea`组件`rows`属性设置成`'auto'`时,组件的高度将会自适应,此时组件从1行高度开始,根据内容自动调整高度。
|
|
7
|
+
你也可以通过对象`{min, max}`来设置文本框最小和最大的自动调整行数。
|
|
8
|
+
|
|
9
|
+
> 自适应高度,文本框将禁用鼠标拖拽调整大小
|
|
10
|
+
|
|
11
|
+
```vdt
|
|
12
|
+
import {Input} from 'kpc';
|
|
13
|
+
|
|
14
|
+
<div>
|
|
15
|
+
<Input
|
|
16
|
+
v-model="value1"
|
|
17
|
+
type="textarea"
|
|
18
|
+
placeholder="please enter"
|
|
19
|
+
fluid
|
|
20
|
+
rows="auto"
|
|
21
|
+
/>
|
|
22
|
+
<br />
|
|
23
|
+
<br />
|
|
24
|
+
<Input
|
|
25
|
+
v-model="value2"
|
|
26
|
+
type="textarea"
|
|
27
|
+
placeholder="please enter"
|
|
28
|
+
fluid
|
|
29
|
+
rows={{min: 3, max: 5}}
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
export default class extends Component {
|
|
36
|
+
static template = template;
|
|
37
|
+
static defaults() {
|
|
38
|
+
return {
|
|
39
|
+
value1: '',
|
|
40
|
+
value2: '',
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
@@ -9,9 +9,9 @@ order: 3
|
|
|
9
9
|
import {Input} from 'kpc';
|
|
10
10
|
|
|
11
11
|
<div>
|
|
12
|
-
<Input type="textarea" placeholder="please enter" />
|
|
12
|
+
<Input type="textarea" placeholder="please enter" fluid />
|
|
13
13
|
<br />
|
|
14
14
|
<br />
|
|
15
|
-
<Input type="textarea" rows="5" placeholder="please enter" />
|
|
15
|
+
<Input type="textarea" rows="5" placeholder="please enter" fluid />
|
|
16
16
|
</div>
|
|
17
17
|
```
|
|
@@ -27,6 +27,7 @@ sidebar: doc
|
|
|
27
27
|
| stackClearIcon | 是否将清空按钮覆盖在`suffix`按钮上展示来节省空间 | `boolean` | `false` |
|
|
28
28
|
| frozenOnInput | 是否在输入的过程中冻结`value`更新到视图 | `boolean` | `false` |
|
|
29
29
|
| inline | 是否展示内联模式 | `boolean` | `flase` |
|
|
30
|
+
| resize | 指定textarea输入框拖动调整大小的方向,默认只能垂直方向调整 | `"none"` | `"vertical"` | `"horizontal"` | `"both"`' | `"vertical"` |
|
|
30
31
|
|
|
31
32
|
## Search
|
|
32
33
|
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import BasicDemo from '~/components/input/demos/basic';
|
|
2
|
-
import {mount, unmount, dispatchEvent, wait} from '../../test/utils';
|
|
2
|
+
import {mount, unmount, dispatchEvent, wait, getElement} from '../../test/utils';
|
|
3
3
|
import SearchDemo from '~/components/input/demos/search';
|
|
4
4
|
import FrozenDemo from '~/components/input/demos/frozen';
|
|
5
|
+
import AutoRowsDemo from '~/components/input/demos/autoRows';
|
|
6
|
+
import PasswordDemo from '~/components/input/demos/password';
|
|
7
|
+
import {Input} from './';
|
|
8
|
+
import {Dialog} from '../dialog';
|
|
9
|
+
import { Component } from 'intact';
|
|
5
10
|
|
|
6
11
|
describe('Input', () => {
|
|
7
12
|
afterEach(() => {unmount()});
|
|
@@ -70,4 +75,95 @@ describe('Input', () => {
|
|
|
70
75
|
await wait();
|
|
71
76
|
expect(input2.value).to.eql('#112233');
|
|
72
77
|
});
|
|
78
|
+
|
|
79
|
+
it('should auto expand or shrink textarea', async () => {
|
|
80
|
+
const [instance, element] = mount(AutoRowsDemo);
|
|
81
|
+
const [textarea1, textarea2] = element.querySelectorAll('textarea');
|
|
82
|
+
// const lineHeight = parseInt(getComputedStyle(textarea1).lineHeight);
|
|
83
|
+
|
|
84
|
+
instance.set<string>('value1', 'a\nb');
|
|
85
|
+
await wait();
|
|
86
|
+
expect(textarea1.style.height).to.eql('50px');
|
|
87
|
+
|
|
88
|
+
instance.set<string>('value1', 'a');
|
|
89
|
+
await wait();
|
|
90
|
+
expect(textarea1.style.height).to.eql('32px');
|
|
91
|
+
|
|
92
|
+
instance.set<string>('value2', 'a');
|
|
93
|
+
await wait();
|
|
94
|
+
expect(textarea2.style.height).to.eql('68px');
|
|
95
|
+
|
|
96
|
+
instance.set<string>('value2', 'a\nb\nc')
|
|
97
|
+
await wait();
|
|
98
|
+
expect(textarea2.style.height).to.eql('68px');
|
|
99
|
+
|
|
100
|
+
instance.set<string>('value2', 'a\nb\nc\nd')
|
|
101
|
+
await wait();
|
|
102
|
+
expect(textarea2.style.height).to.eql('86px');
|
|
103
|
+
|
|
104
|
+
instance.set<string>('value2', 'a\nb\nc\nd\ne\nf\ng\nh')
|
|
105
|
+
await wait();
|
|
106
|
+
expect(textarea2.style.height).to.eql('104px');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should show or hide password', async () => {
|
|
110
|
+
const [instance, element] = mount(PasswordDemo);
|
|
111
|
+
const input = element.querySelector<HTMLInputElement>('input')!;
|
|
112
|
+
const icon = element.querySelector<HTMLElement>('.k-icon')!;
|
|
113
|
+
const inputInstance = instance.refs.__demo as Input;
|
|
114
|
+
|
|
115
|
+
icon.click();
|
|
116
|
+
await wait();
|
|
117
|
+
expect(input.type).to.eql('text');
|
|
118
|
+
expect(element.innerHTML).to.matchSnapshot();
|
|
119
|
+
|
|
120
|
+
icon.click();
|
|
121
|
+
await wait();
|
|
122
|
+
expect(input.type).to.eql('password');
|
|
123
|
+
expect(element.innerHTML).to.matchSnapshot();
|
|
124
|
+
|
|
125
|
+
// simulate receive type
|
|
126
|
+
inputInstance.$props.type = 'number';
|
|
127
|
+
(inputInstance as any).trigger('$receive:type', 'number');
|
|
128
|
+
await wait();
|
|
129
|
+
expect(input.type).to.eql('number');
|
|
130
|
+
expect(icon.parentElement!.parentElement).to.eql(null);
|
|
131
|
+
expect(element.innerHTML).to.matchSnapshot();
|
|
132
|
+
|
|
133
|
+
// simulate receive showPassword
|
|
134
|
+
inputInstance.$props.type = 'password';
|
|
135
|
+
inputInstance.$props.showPassword = false;
|
|
136
|
+
(inputInstance as any).trigger('$receive:type', 'password');
|
|
137
|
+
(inputInstance as any).trigger('$receive:showPassword', false);
|
|
138
|
+
await wait();
|
|
139
|
+
expect(input.type).to.eql('password');
|
|
140
|
+
expect(element.querySelector<HTMLElement>('.k-icon')).to.eql(null);
|
|
141
|
+
expect(element.innerHTML).to.matchSnapshot();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should set width when dialog show and input mounted', async () => {
|
|
145
|
+
class Demo extends Component<{show: boolean}> {
|
|
146
|
+
static template = `
|
|
147
|
+
var Dialog = this.Dialog;
|
|
148
|
+
var Input = this.Input;
|
|
149
|
+
<Dialog value={this.get('show')}>
|
|
150
|
+
<Input autoWidth placeholder="test" v-if={this.get('show')} />
|
|
151
|
+
</Dialog>
|
|
152
|
+
`;
|
|
153
|
+
static defaults() {
|
|
154
|
+
return {
|
|
155
|
+
show: false,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
private Dialog = Dialog;
|
|
159
|
+
private Input = Input;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const [instance] = mount(Demo);
|
|
163
|
+
instance.set('show', true);
|
|
164
|
+
await wait(50);
|
|
165
|
+
const dialog = getElement('.k-dialog')!;
|
|
166
|
+
const width = parseInt(dialog.querySelector<HTMLInputElement>('.k-input-inner')!.style.width);
|
|
167
|
+
expect(width).to.gt(1);
|
|
168
|
+
});
|
|
73
169
|
});
|