@king-design/intact 2.0.16 → 2.1.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.
- 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/styles.ts +2 -1
- 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 +18 -10
- package/components/dropdown/item.ts +3 -2
- package/components/dropdown/menu.ts +1 -1
- package/components/dropdown/usePosition.ts +9 -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/pagination/index.spec.ts +1 -1
- package/components/pagination/index.ts +1 -2
- 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/demos/trigger.md +1 -1
- package/components/tooltip/index.md +1 -1
- package/components/tooltip/index.spec.ts +8 -5
- package/components/tooltip/tooltip.ts +0 -2
- package/components/treeSelect/index.md +9 -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/styles.js +1 -1
- 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 +0 -1
- package/es/components/dropdown/dropdown.js +19 -8
- package/es/components/dropdown/item.js +3 -3
- package/es/components/dropdown/menu.js +1 -1
- package/es/components/dropdown/usePosition.js +8 -1
- 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/pagination/index.js +1 -3
- package/es/components/pagination/index.spec.js +2 -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/index.spec.js +9 -10
- package/es/components/tooltip/tooltip.d.ts +0 -1
- package/es/components/tooltip/tooltip.js +1 -12
- 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/dialog/demos/basic/react.js +4 -1
- 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/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 +4 -4
- package/styles/fonts/ionicons.ts +0 -1
|
@@ -30,6 +30,8 @@ sidebar: doc
|
|
|
30
30
|
| loadData | 如果`data`中的`children`属性值为空数组`[]`,则可以使用该属性定义动态加载逻辑,组件会将当前选中的数据项作为参数传入 | `(data: CascaderData<V>) => any` | `undefined` |
|
|
31
31
|
| filter | 如果可搜索,你可以传入`filter`改变搜索逻辑,组件会将搜索关键词和数据项作为参数传入 | `(keywords: string, data: CascaderData<V>) => boolean` | `(keywords: string, data: CascaderData<V>) => data.label.includes(keywords)` |
|
|
32
32
|
| show | 是否展示菜单项 | `boolean` | `false` |
|
|
33
|
+
| fields | 指定`value` `label` `children` `disabled`字段名 | `CascaderFields<CascaderData<any>>` | `{ value: 'value', label: 'label', children: 'children', disabled: 'disabled' }` |
|
|
34
|
+
| position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` | `"left"` | `"bottom"` | `"right"` | `"top"` | `{my: 'left top+8', 'left bottom'}` |
|
|
33
35
|
|
|
34
36
|
```ts
|
|
35
37
|
export type CascaderData<V> = {
|
|
@@ -40,6 +42,22 @@ export type CascaderData<V> = {
|
|
|
40
42
|
children?: CascaderData<V>[]
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
export type CascaderFields<Data> = {
|
|
46
|
+
value?: keyof Data,
|
|
47
|
+
label?: keyof Data,
|
|
48
|
+
children?: keyof Data,
|
|
49
|
+
disabled?: keyof Data,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type Position = {
|
|
53
|
+
my?: string | [string, string]
|
|
54
|
+
at?: string | [string, string]
|
|
55
|
+
collision?: Collision | [Collision, Collision]
|
|
56
|
+
collisionDirection?: ['left'] | ['top'] | ['left', 'top']
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type Collision = 'fit' | 'flip' | 'flipfit' | 'none'
|
|
60
|
+
|
|
43
61
|
export type Container = string | ((parentDom: Element, anchor: Node | null) => Element)
|
|
44
62
|
```
|
|
45
63
|
|
|
@@ -205,4 +205,60 @@ describe('Cascader', () => {
|
|
|
205
205
|
expect(instance.get('value')).to.eql(['hunan', 'haidian']);
|
|
206
206
|
expect(element.textContent).to.eql('湖南 / 海淀区');
|
|
207
207
|
});
|
|
208
|
+
|
|
209
|
+
it('specify fields', async () => {
|
|
210
|
+
class Demo extends Component {
|
|
211
|
+
static template = `
|
|
212
|
+
const {Cascader} = this;
|
|
213
|
+
<Cascader data={this.get('data')}
|
|
214
|
+
v-model="value"
|
|
215
|
+
fields={{value: 'v', label: 'l', children: 'c'}}
|
|
216
|
+
/>
|
|
217
|
+
`;
|
|
218
|
+
static defaults() {
|
|
219
|
+
return {
|
|
220
|
+
value: [],
|
|
221
|
+
data: [
|
|
222
|
+
{
|
|
223
|
+
v: 'beijing',
|
|
224
|
+
l: '北京',
|
|
225
|
+
c: [
|
|
226
|
+
{
|
|
227
|
+
v: 'haidian',
|
|
228
|
+
l: '海淀区'
|
|
229
|
+
},
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
v: 'hunan',
|
|
234
|
+
l: '湖南',
|
|
235
|
+
c: [
|
|
236
|
+
{
|
|
237
|
+
v: 'haidian',
|
|
238
|
+
l: '海淀区'
|
|
239
|
+
},
|
|
240
|
+
]
|
|
241
|
+
},
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
private Cascader = Cascader;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const [instance, element] = mount(Demo);
|
|
249
|
+
const select = element;
|
|
250
|
+
select.click();
|
|
251
|
+
await wait();
|
|
252
|
+
const dropdown1 = getElement('.k-cascader-menu')!;
|
|
253
|
+
const [item1] = dropdown1.querySelectorAll<HTMLElement>(':scope > .k-dropdown-item');
|
|
254
|
+
item1.click();
|
|
255
|
+
await wait();
|
|
256
|
+
expect(dropdown1.innerHTML).to.matchSnapshot();
|
|
257
|
+
const dropdown2 = getElement('.k-cascader-menu')!;
|
|
258
|
+
const [item11,] = dropdown2.querySelectorAll<HTMLElement>(':scope > .k-dropdown-item');
|
|
259
|
+
item11.click();
|
|
260
|
+
await wait();
|
|
261
|
+
expect(element.innerHTML).to.matchSnapshot();
|
|
262
|
+
expect(instance.get('value')).to.eql(['beijing', 'haidian']);
|
|
263
|
+
});
|
|
208
264
|
});
|
|
@@ -7,22 +7,39 @@ import {useValue} from './useValue';
|
|
|
7
7
|
import {useLabel} from './useLabel';
|
|
8
8
|
import {useLoad} from './useLoad';
|
|
9
9
|
import {useFilterable} from './useFilterable';
|
|
10
|
+
import { useFields } from './useFields';
|
|
10
11
|
|
|
11
|
-
export interface CascaderProps<
|
|
12
|
-
|
|
12
|
+
export interface CascaderProps<
|
|
13
|
+
V = any,
|
|
14
|
+
Multipe extends boolean = boolean,
|
|
15
|
+
Data extends BaseCascaderData = CascaderData<V>
|
|
16
|
+
> extends BaseSelectProps<V[], Multipe> {
|
|
17
|
+
data?: Data[],
|
|
13
18
|
trigger?: 'click' | 'hover'
|
|
14
19
|
changeOnSelect?: boolean
|
|
15
20
|
format?: (labels: string[]) => string
|
|
16
|
-
loadData?: (data:
|
|
17
|
-
filter?: (keywords: string, data:
|
|
21
|
+
loadData?: (data: Data) => any
|
|
22
|
+
filter?: (keywords: string, data: Data) => boolean,
|
|
23
|
+
fields?: CascaderFields<Data>,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type CascaderFields<Data> = {
|
|
27
|
+
value?: keyof Data,
|
|
28
|
+
label?: keyof Data,
|
|
29
|
+
children?: keyof Data,
|
|
30
|
+
disabled?: keyof Data,
|
|
18
31
|
}
|
|
19
32
|
|
|
20
|
-
export
|
|
33
|
+
export interface BaseCascaderData {
|
|
34
|
+
loaded?: boolean
|
|
35
|
+
[key: string]: any
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface CascaderData<V> extends BaseCascaderData {
|
|
21
39
|
value: V
|
|
22
40
|
label: string
|
|
23
|
-
disabled?: boolean
|
|
24
|
-
loaded?: boolean
|
|
25
41
|
children?: CascaderData<V>[]
|
|
42
|
+
disabled?: boolean
|
|
26
43
|
}
|
|
27
44
|
|
|
28
45
|
export interface CascaderEvents extends BaseSelectEvents { }
|
|
@@ -37,6 +54,7 @@ const typeDefs: Required<TypeDefs<CascaderProps>> = {
|
|
|
37
54
|
format: Function,
|
|
38
55
|
loadData: Function,
|
|
39
56
|
filter: Function,
|
|
57
|
+
fields: Object,
|
|
40
58
|
};
|
|
41
59
|
|
|
42
60
|
const defaults = (): Partial<CascaderProps> => ({
|
|
@@ -44,21 +62,26 @@ const defaults = (): Partial<CascaderProps> => ({
|
|
|
44
62
|
data: [],
|
|
45
63
|
trigger: 'click',
|
|
46
64
|
format: (labels: string[]) => labels.join(' / '),
|
|
47
|
-
filter: (keywords: string, data: CascaderData<any>) => data.label.includes(keywords),
|
|
48
65
|
});
|
|
49
66
|
|
|
50
67
|
export class Cascader<
|
|
51
68
|
V = any,
|
|
52
69
|
Multipe extends boolean = false,
|
|
53
|
-
|
|
70
|
+
Data extends BaseCascaderData = CascaderData<V>
|
|
71
|
+
> extends BaseSelect<CascaderProps<V, Multipe, Data>, CascaderEvents, CascaderBlocks<V>> {
|
|
54
72
|
static template = template;
|
|
55
73
|
static typeDefs = typeDefs;
|
|
56
74
|
static defaults = defaults;
|
|
57
75
|
|
|
76
|
+
private fields = useFields();
|
|
58
77
|
private value = useValue();
|
|
59
|
-
private label = useLabel();
|
|
60
|
-
private load = useLoad();
|
|
61
|
-
private filterable = useFilterable(
|
|
78
|
+
private label = useLabel(this.fields);
|
|
79
|
+
private load = useLoad(this.fields);
|
|
80
|
+
private filterable = useFilterable(
|
|
81
|
+
this.input.keywords,
|
|
82
|
+
this.value.setValue,
|
|
83
|
+
this.fields
|
|
84
|
+
);
|
|
62
85
|
private positionObj = {my: 'left top', at: 'right top', collisionDirection: ['left']};
|
|
63
86
|
|
|
64
87
|
protected getPlaceholder() {
|
|
@@ -3,12 +3,13 @@ import {Icon} from '../icon';
|
|
|
3
3
|
import {_$} from '../../i18n';
|
|
4
4
|
import {makeMenuStyles, makeFilterMenuStyles} from './styles';
|
|
5
5
|
|
|
6
|
-
const {data, trigger, filterable} = this.get();
|
|
6
|
+
const {data, trigger, filterable, fields} = this.get();
|
|
7
7
|
const baseMenuStyles = makeMenuStyles();
|
|
8
8
|
const classNameObj = {
|
|
9
9
|
'k-cascader-menu': true,
|
|
10
10
|
[baseMenuStyles]: true,
|
|
11
11
|
};
|
|
12
|
+
const getField = this.fields;
|
|
12
13
|
|
|
13
14
|
const {values, isShowed, isSelected, onSelect, toggleShowedValue} = this.value;
|
|
14
15
|
const Options = (data, level, loaded, parentSelected) => {
|
|
@@ -21,15 +22,15 @@ const Options = (data, level, loaded, parentSelected) => {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
return data.map((item, index) => {
|
|
24
|
-
const value = item
|
|
25
|
+
const value = getField(item, 'value');
|
|
25
26
|
const showed = isShowed(value, level);
|
|
26
27
|
const selected = parentSelected && isSelected(value, level);
|
|
27
|
-
const children = item
|
|
28
|
+
const children = getField(item, 'children');
|
|
28
29
|
|
|
29
30
|
const Item = () => {
|
|
30
31
|
return (
|
|
31
32
|
<DropdownItem
|
|
32
|
-
disabled={item
|
|
33
|
+
disabled={getField(item, 'disabled')}
|
|
33
34
|
class={{
|
|
34
35
|
'k-cascader-option': true,
|
|
35
36
|
'k-active': showed,
|
|
@@ -37,7 +38,7 @@ const Options = (data, level, loaded, parentSelected) => {
|
|
|
37
38
|
}}
|
|
38
39
|
ev-select={onSelect.bind(null, value, level)}
|
|
39
40
|
>
|
|
40
|
-
{item
|
|
41
|
+
{getField(item, 'label')}
|
|
41
42
|
<Icon v-if={children}
|
|
42
43
|
class="k-cascader-arrow ion-ios-arrow-right"
|
|
43
44
|
/>
|
|
@@ -50,10 +51,10 @@ const Options = (data, level, loaded, parentSelected) => {
|
|
|
50
51
|
<Dropdown
|
|
51
52
|
position={this.positionObj}
|
|
52
53
|
of="parent"
|
|
53
|
-
disabled={item
|
|
54
|
+
disabled={getField(item, 'disabled')}
|
|
54
55
|
trigger={trigger}
|
|
55
56
|
value={showed}
|
|
56
|
-
ev-$
|
|
57
|
+
ev-$change:value={toggleShowedValue.bind(null, value, level)}
|
|
57
58
|
ev-show={this.load.bind(null, item)}
|
|
58
59
|
>
|
|
59
60
|
{Item()}
|
|
@@ -94,7 +95,7 @@ const {filter, keywords: {value: keywords}, selectByFilter} = this.filterable;
|
|
|
94
95
|
>
|
|
95
96
|
{(() => {
|
|
96
97
|
// highlight keywords
|
|
97
|
-
const label = $value.map(item => item
|
|
98
|
+
const label = $value.map(item => getField(item, 'label')).join(' / ');
|
|
98
99
|
const labels = label.split(keywords);
|
|
99
100
|
const length = labels.length;
|
|
100
101
|
return labels.map((item, index) => {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {useInstance} from 'intact';
|
|
2
|
+
import type {Cascader, CascaderData, BaseCascaderData, CascaderFields} from './';
|
|
3
|
+
|
|
4
|
+
export function useFields() {
|
|
5
|
+
const instance = useInstance() as Cascader;
|
|
6
|
+
|
|
7
|
+
return function getField<
|
|
8
|
+
Data extends BaseCascaderData = CascaderData<unknown>,
|
|
9
|
+
Key extends keyof Data = keyof Data
|
|
10
|
+
>(data: Data, key: Key): Data[Key] {
|
|
11
|
+
const {fields} = instance.get();
|
|
12
|
+
|
|
13
|
+
if (fields) {
|
|
14
|
+
const field = fields[key as keyof CascaderFields<Data>] as Key;
|
|
15
|
+
if (field) {
|
|
16
|
+
return data[field];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return data[key];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
import {useInstance} from 'intact';
|
|
2
|
-
import type {Cascader, CascaderData} from './';
|
|
2
|
+
import type {Cascader, CascaderData, BaseCascaderData} from './';
|
|
3
3
|
import {State} from '../../hooks/useState';
|
|
4
|
-
import type {Value} from './useValue'
|
|
4
|
+
import type {Value} from './useValue';
|
|
5
|
+
import type {useFields} from './useFields';
|
|
5
6
|
|
|
6
7
|
export function useFilterable(
|
|
7
8
|
keywords: State<string>,
|
|
8
9
|
setValue: (value: Value) => void,
|
|
10
|
+
getField: ReturnType<typeof useFields>
|
|
9
11
|
) {
|
|
10
12
|
const instance = useInstance() as Cascader;
|
|
11
13
|
|
|
12
14
|
function filter() {
|
|
13
|
-
const {data, filter} = instance.get();
|
|
14
15
|
const ret: CascaderData<any>[][] = [];
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
let {data, filter} = instance.get();
|
|
18
|
+
if (!filter) {
|
|
19
|
+
filter = (keywords: string, data: CascaderData<any>) => {
|
|
20
|
+
return getField(data, 'label').includes(keywords);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const loop = (
|
|
25
|
+
data: CascaderData<any>[],
|
|
26
|
+
prefix: CascaderData<any>[] = [],
|
|
27
|
+
valid = false,
|
|
28
|
+
disabled = false
|
|
29
|
+
) => {
|
|
17
30
|
data.forEach(item => {
|
|
18
31
|
const _valid = valid || filter!(keywords.value, item);
|
|
19
|
-
const _disabled = disabled || item
|
|
32
|
+
const _disabled = disabled || getField(item, 'disabled');
|
|
20
33
|
const _prefix = prefix.slice(0);
|
|
21
34
|
_prefix.push(item);
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
|
|
36
|
+
const children = getField(item, 'children');
|
|
37
|
+
if (children) {
|
|
38
|
+
loop(children, _prefix, _valid, _disabled);
|
|
24
39
|
} else if (_valid) {
|
|
25
40
|
(_prefix as any).disabled = _disabled;
|
|
26
41
|
ret.push(_prefix);
|
|
@@ -33,7 +48,7 @@ export function useFilterable(
|
|
|
33
48
|
}
|
|
34
49
|
|
|
35
50
|
function selectByFilter(data: CascaderData<any>[]) {
|
|
36
|
-
const value = data.map(item => item
|
|
51
|
+
const value = data.map(item => getField(item, 'value'));
|
|
37
52
|
setValue(value);
|
|
38
53
|
}
|
|
39
54
|
|
|
@@ -3,11 +3,14 @@ import type {Cascader, CascaderData} from './';
|
|
|
3
3
|
import {useState, watchState} from '../../hooks/useState';
|
|
4
4
|
import {isNullOrUndefined} from 'intact-shared';
|
|
5
5
|
import {useBaseLabel} from '../select/useBaseLabel';
|
|
6
|
+
import type {useFields} from './useFields';
|
|
6
7
|
|
|
7
8
|
// treat value as string
|
|
8
9
|
type CascaderStringData = CascaderData<string>
|
|
9
10
|
|
|
10
|
-
export function useLabel(
|
|
11
|
+
export function useLabel(
|
|
12
|
+
getField: ReturnType<typeof useFields>
|
|
13
|
+
) {
|
|
11
14
|
const instance = useInstance() as Cascader;
|
|
12
15
|
|
|
13
16
|
function findLabel(data: CascaderStringData[], value: string[]) {
|
|
@@ -19,10 +22,10 @@ export function useLabel() {
|
|
|
19
22
|
|
|
20
23
|
for (let i = 0; i < data.length; i++) {
|
|
21
24
|
const item = data[i];
|
|
22
|
-
if (item
|
|
23
|
-
labels.push(item
|
|
25
|
+
if (getField(item, 'value') === value[level]) {
|
|
26
|
+
labels.push(getField(item, 'label'));
|
|
24
27
|
|
|
25
|
-
const children = item
|
|
28
|
+
const children = getField(item, 'children');
|
|
26
29
|
if (children) {
|
|
27
30
|
loop(children, level + 1);
|
|
28
31
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {useInstance} from 'intact';
|
|
2
2
|
import type {Cascader, CascaderData} from './';
|
|
3
|
+
import type {useFields} from './useFields';
|
|
3
4
|
|
|
4
|
-
export function useLoad() {
|
|
5
|
+
export function useLoad(getField: ReturnType<typeof useFields>) {
|
|
5
6
|
const instance = useInstance() as Cascader;
|
|
6
7
|
|
|
7
8
|
async function loadData(item: CascaderData<any>) {
|
|
8
9
|
const {loadData} = instance.get();
|
|
9
10
|
if (!loadData) return;
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
const children = getField(item, 'children');
|
|
13
|
+
if (children && !children.length && !item.loaded) {
|
|
12
14
|
await loadData(item);
|
|
13
15
|
item.loaded = true;
|
|
14
16
|
instance.forceUpdate();
|
|
@@ -12,7 +12,7 @@ order: 0
|
|
|
12
12
|
> `import {Code} from '@king-design/react';`
|
|
13
13
|
|
|
14
14
|
组件可以通过`v-model`双向绑定编辑的代码,通过`height`指定组件的高度(需要带单位),默认`100%`;通过
|
|
15
|
-
`language`可以指定编程语言,默认为`
|
|
15
|
+
`language`可以指定编程语言,默认为`javascript`
|
|
16
16
|
|
|
17
17
|
> `Code`组件基于[Monaco Editor@0.26](https://github.com/Microsoft/monaco-editor),使用该组件之前,你需要
|
|
18
18
|
> 安装[monaco-editor-webpack-plugin@4](https://github.com/Microsoft/monaco-editor-webpack-plugin)插件,
|
|
@@ -14,3 +14,19 @@ sidebar: doc
|
|
|
14
14
|
| size | 组件尺寸 | `"large"` | `"default"` | `"small"` | `"mini"` | `"default"` |
|
|
15
15
|
| disabled | 是否禁用 | `boolean` | `false` |
|
|
16
16
|
| show | 是否展示颜色选择面板 | `boolean` | `false` |
|
|
17
|
+
| container | 指定弹出菜单追加的位置,默认:`Dialog`类型的组件会追加到`Dialog`中,其他会追加到`body`中。你可以传入函数返回一个DOM用来作为插入的容器,或者传入字符串用来给`querySelector`进行查询 | `Container` | `undefined` |
|
|
18
|
+
| position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` | `"left"` | `"bottom"` | `"right"` | `"top"` | `{my: 'left top+8', 'left bottom', collison: 'fit'}` |
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
type Position = {
|
|
22
|
+
my?: string | [string, string]
|
|
23
|
+
at?: string | [string, string]
|
|
24
|
+
collision?: Collision | [Collision, Collision]
|
|
25
|
+
collisionDirection?: ['left'] | ['top'] | ['left', 'top']
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type Collision = 'fit' | 'flip' | 'flipfit' | 'none'
|
|
29
|
+
|
|
30
|
+
export type Container = string | ((parentDom: Element, anchor: Node | null) => Element)
|
|
31
|
+
```
|
|
32
|
+
|
|
@@ -2,6 +2,7 @@ import {Component, TypeDefs} from 'intact';
|
|
|
2
2
|
import template from './index.vdt';
|
|
3
3
|
import {sizes, Sizes} from '../../styles/utils';
|
|
4
4
|
import {Container} from '../portal';
|
|
5
|
+
import {Dropdown, DropdownProps} from '../dropdown';
|
|
5
6
|
|
|
6
7
|
export interface ColorpickerProps {
|
|
7
8
|
value: string
|
|
@@ -10,6 +11,7 @@ export interface ColorpickerProps {
|
|
|
10
11
|
disabled?: boolean
|
|
11
12
|
container?: Container
|
|
12
13
|
show?: boolean
|
|
14
|
+
position?: DropdownProps['position']
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export interface ColorpickerEvents { }
|
|
@@ -24,6 +26,7 @@ const typeDefs: Required<TypeDefs<ColorpickerProps>> = {
|
|
|
24
26
|
disabled: Boolean,
|
|
25
27
|
container: [Function, String],
|
|
26
28
|
show: Boolean,
|
|
29
|
+
position: Dropdown.typeDefs.position,
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
const defaults = (): Partial<ColorpickerProps> => ({
|
|
@@ -33,6 +36,7 @@ const defaults = (): Partial<ColorpickerProps> => ({
|
|
|
33
36
|
'#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF'
|
|
34
37
|
],
|
|
35
38
|
size: 'default',
|
|
39
|
+
position: {collision: 'fit'},
|
|
36
40
|
});
|
|
37
41
|
|
|
38
42
|
export class Colorpicker extends Component<ColorpickerProps, ColorpickerEvents> {
|
|
@@ -6,7 +6,8 @@ import {Dropdown, DropdownMenu} from '../dropdown';
|
|
|
6
6
|
|
|
7
7
|
const {
|
|
8
8
|
className, transition, presets,
|
|
9
|
-
value, size, disabled, container
|
|
9
|
+
value, size, disabled, container,
|
|
10
|
+
position,
|
|
10
11
|
} = this.get();
|
|
11
12
|
|
|
12
13
|
const classNameObj = {
|
|
@@ -19,7 +20,7 @@ const classNameObj = {
|
|
|
19
20
|
|
|
20
21
|
<div class={classNameObj} {...getRestProps(this)}>
|
|
21
22
|
<Dropdown
|
|
22
|
-
position={
|
|
23
|
+
position={position}
|
|
23
24
|
trigger="click"
|
|
24
25
|
disabled={disabled}
|
|
25
26
|
container={container}
|
|
@@ -31,6 +31,7 @@ sidebar: doc
|
|
|
31
31
|
| type | 组件类型:`"date"` 只选择日期;`"datetime"` 选择日期和时间;`"year"` 选择年份;`"month"` 选择月份 | `"date"` | `"datetime"` | `"year"` | `"month"` | `"date"` |
|
|
32
32
|
| shortcuts | 指定快捷方式 | `Shortcut[]` | `undefined` |
|
|
33
33
|
| show | 是否展示菜单项 | `boolean` | `false` |
|
|
34
|
+
| position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` | `"left"` | `"bottom"` | `"right"` | `"top"` | `{my: 'left top+8', 'left bottom'}` |
|
|
34
35
|
|
|
35
36
|
```ts
|
|
36
37
|
import {Dayjs} from 'dayjs';
|
|
@@ -41,6 +42,16 @@ export type Shortcut = {
|
|
|
41
42
|
label: (() => string | VNode) | string | VNode
|
|
42
43
|
value: () => Value | [Value, Value]
|
|
43
44
|
}
|
|
45
|
+
|
|
46
|
+
type Position = {
|
|
47
|
+
my?: string | [string, string]
|
|
48
|
+
at?: string | [string, string]
|
|
49
|
+
collision?: Collision | [Collision, Collision]
|
|
50
|
+
collisionDirection?: ['left'] | ['top'] | ['left', 'top']
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type Collision = 'fit' | 'flip' | 'flipfit' | 'none'
|
|
54
|
+
|
|
44
55
|
export type Container = string | ((parentDom: Element, anchor: Node | null) => Element)
|
|
45
56
|
```
|
|
46
57
|
|
|
@@ -114,7 +114,7 @@ describe('Dialog', () => {
|
|
|
114
114
|
dispatchEvent(document, 'keydown', {keyCode: 27});
|
|
115
115
|
expect(instance.get('show')).be.false;
|
|
116
116
|
await wait(500);
|
|
117
|
-
expect(document.body.getAttribute('style')).to.be.
|
|
117
|
+
expect(!!document.body.getAttribute('style')).to.be.false;
|
|
118
118
|
});
|
|
119
119
|
|
|
120
120
|
it('methods test', async () => {
|
|
@@ -156,7 +156,7 @@ describe('Dialog', () => {
|
|
|
156
156
|
unmount();
|
|
157
157
|
}
|
|
158
158
|
await wait(500);
|
|
159
|
-
expect(document.body.getAttribute('style')).to.be.
|
|
159
|
+
expect(!!document.body.getAttribute('style')).to.be.false;
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
it('async close', async () => {
|
|
@@ -62,7 +62,6 @@ const typeDefs: Required<TypeDefs<DropdownProps>> = {
|
|
|
62
62
|
|
|
63
63
|
const defaults = (): Partial<DropdownProps> => ({
|
|
64
64
|
trigger: 'hover',
|
|
65
|
-
position: {},
|
|
66
65
|
of: 'self',
|
|
67
66
|
});
|
|
68
67
|
|
|
@@ -126,10 +125,7 @@ export class Dropdown<
|
|
|
126
125
|
|
|
127
126
|
return [
|
|
128
127
|
clonedTrigger,
|
|
129
|
-
|
|
130
|
-
this.alwaysPortal || !this.rootDropdown ?
|
|
131
|
-
h(Portal, {children: menu, container: this.get('container')}) :
|
|
132
|
-
menu
|
|
128
|
+
h(Portal, {children: menu, container: this.get('container')})
|
|
133
129
|
];
|
|
134
130
|
};
|
|
135
131
|
|
|
@@ -139,8 +135,6 @@ export class Dropdown<
|
|
|
139
135
|
public showedDropdown: Dropdown | null = null;
|
|
140
136
|
public positionHook = usePosition();
|
|
141
137
|
|
|
142
|
-
protected alwaysPortal = false;
|
|
143
|
-
|
|
144
138
|
private timer: number | undefined = undefined;
|
|
145
139
|
private triggerProps: any = null;
|
|
146
140
|
|
|
@@ -294,9 +288,10 @@ export class Dropdown<
|
|
|
294
288
|
function useDocumentClickForDropdown(dropdown: Dropdown) {
|
|
295
289
|
const elementRef = () => findDomFromVNode(dropdown.menuVNode!, true) as Element;
|
|
296
290
|
const [addDocumentClick, removeDocumentClick] = useDocumentClick(elementRef, (e) => {
|
|
297
|
-
// case 1: if click
|
|
298
|
-
// case 2: if right click on trigger and
|
|
299
|
-
// case 3: if click on trigger and
|
|
291
|
+
// case 1: if click a trigger and its trigger type is hover, ignore it
|
|
292
|
+
// case 2: if right click on a trigger and its trigger type is contextmenu, ignore it
|
|
293
|
+
// case 3: if click on a trigger and its trigger type is focus, do nothing
|
|
294
|
+
// case 3: if click on sub-dropdown, we should also show the parent dropdown, so ignore it
|
|
300
295
|
const trigger = dropdown.get('trigger');
|
|
301
296
|
if (trigger === 'focus') return;
|
|
302
297
|
|
|
@@ -310,6 +305,8 @@ function useDocumentClickForDropdown(dropdown: Dropdown) {
|
|
|
310
305
|
}
|
|
311
306
|
}
|
|
312
307
|
|
|
308
|
+
if (isSubDropdownElement(e.target as Element, dropdown)) return;
|
|
309
|
+
|
|
313
310
|
dropdown.hide(true);
|
|
314
311
|
}, true);
|
|
315
312
|
|
|
@@ -317,6 +314,17 @@ function useDocumentClickForDropdown(dropdown: Dropdown) {
|
|
|
317
314
|
dropdown.on('hide', removeDocumentClick);
|
|
318
315
|
}
|
|
319
316
|
|
|
317
|
+
function isSubDropdownElement(elem: Element, dropdown: Dropdown): boolean {
|
|
318
|
+
const showedDropdown = dropdown.showedDropdown;
|
|
319
|
+
if (!showedDropdown) return false;
|
|
320
|
+
|
|
321
|
+
const subMenuElement = findDomFromVNode(showedDropdown.menuVNode!, true) as Element;
|
|
322
|
+
if (containsOrEqual(subMenuElement, elem)) {
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
return isSubDropdownElement(elem, showedDropdown);
|
|
326
|
+
}
|
|
327
|
+
|
|
320
328
|
function useHideLastMenuOnShow(dropdown: Dropdown) {
|
|
321
329
|
const parentDropdown = dropdown.dropdown;
|
|
322
330
|
dropdown.on('show', () => {
|
|
@@ -52,14 +52,15 @@ export class DropdownItem extends Component<DropdownItemProps, DropdownItemEvent
|
|
|
52
52
|
select() {
|
|
53
53
|
if (this.parentDropdown) return;
|
|
54
54
|
|
|
55
|
+
// trigger select event firstly for Cascader update values
|
|
56
|
+
this.trigger('select');
|
|
57
|
+
|
|
55
58
|
if (this.get('hideOnSelect')) {
|
|
56
59
|
// hide all dropdowns
|
|
57
60
|
let dropdown = this.dropdown;
|
|
58
61
|
do { dropdown!.hide(true); }
|
|
59
62
|
while (dropdown = dropdown!.dropdown);
|
|
60
63
|
}
|
|
61
|
-
|
|
62
|
-
this.trigger('select');
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
hasSubMenu() {
|
|
@@ -63,7 +63,7 @@ function useKeyboardForDropdownMenu(dropdown: Dropdown) {
|
|
|
63
63
|
const focus = () => focusByIndex(0);
|
|
64
64
|
|
|
65
65
|
// In Cascader the menu may have been replaced by another menu, in this case,
|
|
66
|
-
// if the dropdown has showed
|
|
66
|
+
// if the dropdown has showed while we mounted the menu, add keydown listener
|
|
67
67
|
if (dropdown.get('value')) {
|
|
68
68
|
onShow();
|
|
69
69
|
}
|
|
@@ -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,14 @@ 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
|
+
JSON.stringify(newValue) === JSON.stringify(oldValue)
|
|
25
|
+
) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
20
28
|
if (instance.get('value')) {
|
|
21
29
|
handle(noop);
|
|
22
30
|
}
|
|
@@ -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
|