@king-design/intact 2.0.1 → 2.0.4
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.spec.ts +59 -0
- package/components/cascader/index.vdt +4 -4
- package/components/cascader/useLabel.ts +9 -9
- package/components/dropdown/dropdown.ts +5 -6
- package/components/form/index.spec.ts +1 -1
- package/components/menu/demos/collapse.md +3 -1
- package/components/menu/index.spec.ts +10 -4
- package/components/menu/item.ts +5 -4
- package/components/menu/item.vdt +3 -3
- package/components/menu/menu.ts +4 -0
- package/components/menu/useExpanded.ts +1 -1
- package/components/menu/useHighlight.ts +45 -40
- package/components/portal.ts +1 -1
- package/components/skeleton/demos/animate.md +30 -0
- package/components/skeleton/demos/avator.md +30 -0
- package/components/skeleton/demos/basic.md +30 -0
- package/components/skeleton/demos/custom.md +39 -0
- package/components/skeleton/demos/rows.md +32 -0
- package/components/skeleton/index.md +24 -0
- package/components/skeleton/index.ts +2 -0
- package/components/skeleton/item.ts +30 -0
- package/components/skeleton/item.vdt +28 -0
- package/components/skeleton/skeleton.ts +33 -0
- package/components/skeleton/skeleton.vdt +32 -0
- package/components/skeleton/style.ts +105 -0
- package/components/tree/useFilter.ts +1 -2
- package/es/components/cascader/index.spec.js +88 -0
- package/es/components/cascader/index.vdt.js +4 -4
- package/es/components/cascader/useLabel.js +8 -12
- package/es/components/dropdown/dropdown.js +7 -7
- package/es/components/form/index.spec.js +2 -4
- package/es/components/menu/index.spec.js +13 -6
- package/es/components/menu/item.d.ts +0 -1
- package/es/components/menu/item.js +6 -4
- package/es/components/menu/item.vdt.js +4 -4
- package/es/components/menu/menu.d.ts +3 -0
- package/es/components/menu/menu.js +4 -0
- package/es/components/menu/useExpanded.d.ts +1 -4
- package/es/components/menu/useHighlight.d.ts +5 -8
- package/es/components/menu/useHighlight.js +44 -33
- package/es/components/portal.js +1 -1
- package/es/components/skeleton/index.d.ts +2 -0
- package/es/components/skeleton/index.js +2 -0
- package/es/components/skeleton/item.d.ts +16 -0
- package/es/components/skeleton/item.js +26 -0
- package/es/components/skeleton/item.vdt.js +35 -0
- package/es/components/skeleton/skeleton.d.ts +17 -0
- package/es/components/skeleton/skeleton.js +30 -0
- package/es/components/skeleton/skeleton.vdt.js +37 -0
- package/es/components/skeleton/style.d.ts +6 -0
- package/es/components/skeleton/style.js +35 -0
- package/es/components/tree/useFilter.js +1 -2
- package/es/index.d.ts +3 -2
- package/es/index.js +3 -2
- package/es/packages/kpc-react/__tests__/components/form.spec.d.ts +1 -0
- package/es/packages/kpc-react/__tests__/components/form.spec.js +46 -0
- package/es/site/data/components/menu/demos/collapse/index.js +1 -0
- package/es/site/data/components/menu/demos/collapse/react.js +7 -0
- package/es/site/data/components/skeleton/demos/animate/index.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/animate/index.js +23 -0
- package/es/site/data/components/skeleton/demos/animate/react.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/animate/react.js +38 -0
- package/es/site/data/components/skeleton/demos/avator/index.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/avator/index.js +23 -0
- package/es/site/data/components/skeleton/demos/avator/react.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/avator/react.js +37 -0
- package/es/site/data/components/skeleton/demos/basic/index.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/basic/index.js +23 -0
- package/es/site/data/components/skeleton/demos/basic/react.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/basic/react.js +36 -0
- package/es/site/data/components/skeleton/demos/custom/index.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/custom/index.js +23 -0
- package/es/site/data/components/skeleton/demos/custom/react.d.ts +11 -0
- package/es/site/data/components/skeleton/demos/custom/react.js +60 -0
- package/es/site/data/components/skeleton/demos/rows/index.d.ts +13 -0
- package/es/site/data/components/skeleton/demos/rows/index.js +24 -0
- package/es/site/data/components/skeleton/demos/rows/react.d.ts +13 -0
- package/es/site/data/components/skeleton/demos/rows/react.js +38 -0
- package/es/site/data/components/skeleton/index.d.ts +57 -0
- package/es/site/data/components/skeleton/index.js +42 -0
- package/es/site/src/client.js +4 -4
- package/es/site/src/components/footer/styles.js +1 -1
- package/es/site/src/pages/colorProcess/index.d.ts +21 -0
- package/es/site/src/pages/colorProcess/index.js +79 -0
- package/es/site/src/pages/colorProcess/style.d.ts +3 -0
- package/es/site/src/pages/colorProcess/style.js +53 -0
- package/es/site/src/pages/font/index.d.ts +12 -0
- package/es/site/src/pages/font/index.js +22 -0
- package/es/site/src/pages/font/styles.d.ts +1 -0
- package/es/site/src/pages/font/styles.js +9 -0
- package/es/site/src/pages/iframe/colorProcess/styles.js +2 -2
- package/es/site/src/pages/index/BestPractice/styles.js +1 -1
- package/es/site/src/pages/index/ColorProcess/styles.js +2 -2
- package/es/site/src/pages/index/KingVersion/styles.js +1 -1
- package/es/site/src/pages/index/NewFunction/index.d.ts +2 -0
- package/es/site/src/pages/index/NewFunction/index.js +8 -2
- package/es/site/src/pages/index/NewFunction/styles.js +1 -1
- package/es/site/src/pages/index/styles.js +2 -1
- package/es/site/src/pages/resource/index.d.ts +1 -0
- package/es/site/src/pages/resource/index.js +4 -1
- package/es/site/src/pages/styles.js +1 -1
- package/es/site/src/router/index.js +75 -5
- package/index.ts +3 -2
- package/package.json +5 -4
|
@@ -5,6 +5,7 @@ import LoadDataDemo from '~/components/cascader/demos/loadData';
|
|
|
5
5
|
import FilterDemo from '~/components/cascader/demos/filterable';
|
|
6
6
|
import {mount, unmount, dispatchEvent, getElement, getElements, wait} from '../../test/utils';
|
|
7
7
|
import {Cascader} from './';
|
|
8
|
+
import {Component} from 'intact';
|
|
8
9
|
|
|
9
10
|
describe('Cascader', () => {
|
|
10
11
|
afterEach(async () => {
|
|
@@ -146,4 +147,62 @@ describe('Cascader', () => {
|
|
|
146
147
|
expect(dropdown.innerHTML).to.matchSnapshot();
|
|
147
148
|
expect(dropdown.innerText).to.eql('无数据');
|
|
148
149
|
});
|
|
150
|
+
|
|
151
|
+
it('duplicated sub data', async () => {
|
|
152
|
+
class Demo extends Component {
|
|
153
|
+
static template = `const {Cascader} = this; <Cascader data={this.get('data')} v-model="value" />`;
|
|
154
|
+
static defaults() {
|
|
155
|
+
return {
|
|
156
|
+
value: ['beijing', 'haidian'],
|
|
157
|
+
data: [
|
|
158
|
+
{
|
|
159
|
+
value: 'beijing',
|
|
160
|
+
label: '北京',
|
|
161
|
+
children: [
|
|
162
|
+
{
|
|
163
|
+
value: 'haidian',
|
|
164
|
+
label: '海淀区'
|
|
165
|
+
},
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
value: 'hunan',
|
|
170
|
+
label: '湖南',
|
|
171
|
+
children: [
|
|
172
|
+
{
|
|
173
|
+
value: 'haidian',
|
|
174
|
+
label: '海淀区'
|
|
175
|
+
},
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
private Cascader = Cascader;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const [instance, element] = mount(Demo);
|
|
185
|
+
dispatchEvent(element, 'click');
|
|
186
|
+
await wait();
|
|
187
|
+
|
|
188
|
+
const [dropdown1, dropdown2] = getElements('.k-cascader-menu');
|
|
189
|
+
const [item1, item2] = dropdown1.querySelectorAll(':scope > .k-dropdown-item');
|
|
190
|
+
expect(item1.classList.contains('k-selected')).to.be.true;
|
|
191
|
+
expect(item2.classList.contains('k-selected')).to.be.false;
|
|
192
|
+
const [item21] = dropdown2.querySelectorAll(':scope > .k-dropdown-item');
|
|
193
|
+
expect(item21.classList.contains('k-selected')).to.be.true;
|
|
194
|
+
|
|
195
|
+
dispatchEvent(item2, 'click');
|
|
196
|
+
await wait();
|
|
197
|
+
|
|
198
|
+
const dropdown3 = getElement('.k-cascader-menu')!;
|
|
199
|
+
const [item31] = dropdown3.querySelectorAll(':scope > .k-dropdown-item');
|
|
200
|
+
expect(item31.classList.contains('k-selected')).to.be.false;
|
|
201
|
+
|
|
202
|
+
dispatchEvent(item31, 'click');
|
|
203
|
+
await wait();
|
|
204
|
+
|
|
205
|
+
expect(instance.get('value')).to.eql(['hunan', 'haidian']);
|
|
206
|
+
expect(element.textContent).to.eql('湖南 / 海淀区');
|
|
207
|
+
});
|
|
149
208
|
});
|
|
@@ -11,7 +11,7 @@ const classNameObj = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
const {values, isShowed, isSelected, onSelect, toggleShowedValue} = this.value;
|
|
14
|
-
const Options = (data, level, loaded) => {
|
|
14
|
+
const Options = (data, level, loaded, parentSelected) => {
|
|
15
15
|
if (!data.length) {
|
|
16
16
|
if (!loaded) {
|
|
17
17
|
return <Icon class="ion-load-c k-cascader-loading" rotate />
|
|
@@ -23,7 +23,7 @@ const Options = (data, level, loaded) => {
|
|
|
23
23
|
return data.map((item, index) => {
|
|
24
24
|
const value = item.value;
|
|
25
25
|
const showed = isShowed(value, level);
|
|
26
|
-
const selected = isSelected(value, level);
|
|
26
|
+
const selected = parentSelected && isSelected(value, level);
|
|
27
27
|
const children = item.children;
|
|
28
28
|
|
|
29
29
|
const Item = () => {
|
|
@@ -58,7 +58,7 @@ const Options = (data, level, loaded) => {
|
|
|
58
58
|
>
|
|
59
59
|
{Item()}
|
|
60
60
|
<DropdownMenu class={classNameObj}>
|
|
61
|
-
{showed ? Options(children, level + 1, item.loaded) : null}
|
|
61
|
+
{showed ? Options(children, level + 1, item.loaded, selected) : null}
|
|
62
62
|
</DropdownMenu>
|
|
63
63
|
</Dropdown> :
|
|
64
64
|
Item()
|
|
@@ -74,7 +74,7 @@ const {filter, keywords: {value: keywords}, selectByFilter} = this.filterable;
|
|
|
74
74
|
class={classNameObj}
|
|
75
75
|
key="common"
|
|
76
76
|
>
|
|
77
|
-
{Options(data, 0, true)}
|
|
77
|
+
{Options(data, 0, true, true)}
|
|
78
78
|
</DropdownMenu>
|
|
79
79
|
<DropdownMenu v-else
|
|
80
80
|
key="filter"
|
|
@@ -14,23 +14,23 @@ export function useLabel() {
|
|
|
14
14
|
const {format} = instance.get();
|
|
15
15
|
const labels: string[] = [];
|
|
16
16
|
const length = value.length;
|
|
17
|
-
const loop = (data: CascaderStringData[]) => {
|
|
17
|
+
const loop = (data: CascaderStringData[], level: number) => {
|
|
18
|
+
if (level === length) return;
|
|
19
|
+
|
|
18
20
|
for (let i = 0; i < data.length; i++) {
|
|
19
21
|
const item = data[i];
|
|
20
|
-
if (
|
|
22
|
+
if (item.value === value[level]) {
|
|
21
23
|
labels.push(item.label);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
const children = item.children;
|
|
26
|
+
if (children) {
|
|
27
|
+
loop(children, level + 1);
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
|
-
const children = item.children;
|
|
27
|
-
if (children) {
|
|
28
|
-
loop(children);
|
|
29
|
-
}
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
loop(data);
|
|
33
|
+
loop(data, 0);
|
|
34
34
|
|
|
35
35
|
return labels.length ? format!(labels) : null;
|
|
36
36
|
}
|
|
@@ -244,10 +244,12 @@ export class Dropdown<
|
|
|
244
244
|
|
|
245
245
|
private normalizeTriggerProps(props: any) {
|
|
246
246
|
// if use kpc in react or vue, normalize props by Wrapper.props.vnode;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (!vnode) return props;
|
|
247
|
+
const vnode = props.vnode;
|
|
248
|
+
if (!vnode) return props;
|
|
250
249
|
|
|
250
|
+
// maybe we render the intact component in react slot property, in this case
|
|
251
|
+
// the $isReact is false. so use the vnode $$typeof field as gauge
|
|
252
|
+
if (vnode.$$typeof || (this as any).$isVueNext) {
|
|
251
253
|
const _props = vnode.props;
|
|
252
254
|
if (!_props) return props;
|
|
253
255
|
|
|
@@ -260,9 +262,6 @@ export class Dropdown<
|
|
|
260
262
|
className: _props.className || _props.class /* vue-next */,
|
|
261
263
|
};
|
|
262
264
|
} else if ((this as any).$isVue) {
|
|
263
|
-
const vnode = props.vnode;
|
|
264
|
-
if (!vnode) return props;
|
|
265
|
-
|
|
266
265
|
const data = vnode.data;
|
|
267
266
|
const on = data && data.on || EMPTY_OBJ;
|
|
268
267
|
const ret: Record<string, any> = {vnode};
|
|
@@ -21,7 +21,7 @@ RemoteDemo.prototype.validateUserName = function(value) {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
describe('Form', () => {
|
|
24
|
-
afterEach(() => unmount());
|
|
24
|
+
// afterEach(() => unmount());
|
|
25
25
|
|
|
26
26
|
it('validate', async () => {
|
|
27
27
|
const [instance, element] = mount(BasicDemo, null, basicDemoData);
|
|
@@ -24,7 +24,8 @@ import {Menu, MenuItem, Switch, Icon} from 'kpc';
|
|
|
24
24
|
falseValue="dark"
|
|
25
25
|
/>
|
|
26
26
|
<br /><br />
|
|
27
|
-
<Menu v-model:expandedKeys="expandedKeys"
|
|
27
|
+
<Menu v-model:expandedKeys="expandedKeys"
|
|
28
|
+
v-model:selectedKey="selectedKey"
|
|
28
29
|
collapse={this.get('collapse')}
|
|
29
30
|
theme={this.get('theme')}
|
|
30
31
|
ref="__test"
|
|
@@ -62,6 +63,7 @@ export default class extends Component<Props> {
|
|
|
62
63
|
static defaults() {
|
|
63
64
|
return {
|
|
64
65
|
expandedKeys: ['3'],
|
|
66
|
+
selectedKey: '3-2',
|
|
65
67
|
collapse: false,
|
|
66
68
|
theme: 'dark'
|
|
67
69
|
} as MenuProps;
|
|
@@ -22,23 +22,29 @@ describe('Menu', () => {
|
|
|
22
22
|
|
|
23
23
|
it('select', async () => {
|
|
24
24
|
const [instance, element] = mount(CollapseDemo);
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
expect(element.innerHTML).to.matchSnapshot();
|
|
26
27
|
|
|
27
28
|
const [title, disabledTitle] = element.querySelectorAll<HTMLElement>('.k-menu-title');
|
|
28
29
|
title.click();
|
|
29
30
|
await wait();
|
|
30
31
|
expect(element.outerHTML).to.matchSnapshot();
|
|
31
|
-
expect(
|
|
32
|
+
expect(instance.get('selectedKey')).to.eql('1');
|
|
32
33
|
disabledTitle.click();
|
|
33
34
|
await wait();
|
|
34
35
|
expect(element.outerHTML).to.matchSnapshot();
|
|
35
|
-
expect(
|
|
36
|
+
expect(instance.get('selectedKey')).to.eql('1');
|
|
36
37
|
|
|
37
38
|
const subTitle = element.querySelector('.k-expanded .k-menu .k-menu-title') as HTMLElement;
|
|
38
39
|
subTitle.click();
|
|
39
40
|
await wait();
|
|
40
41
|
expect(element.outerHTML).to.matchSnapshot();
|
|
41
|
-
expect(
|
|
42
|
+
expect(instance.get('selectedKey')).to.eql('3-1');
|
|
43
|
+
|
|
44
|
+
// clear
|
|
45
|
+
instance.set('selectedKey', '');
|
|
46
|
+
await wait();
|
|
47
|
+
expect(element.querySelector('.k-highlighted')).to.be.null;
|
|
42
48
|
});
|
|
43
49
|
|
|
44
50
|
it('collapse', async () => {
|
package/components/menu/item.ts
CHANGED
|
@@ -4,10 +4,11 @@ import {Dropdown, DropdownMenu} from '../dropdown';
|
|
|
4
4
|
import template from './item.vdt';
|
|
5
5
|
import {bind} from '../utils';
|
|
6
6
|
import {useState} from '../../hooks/useState';
|
|
7
|
-
import {useHighlight} from './useHighlight';
|
|
8
7
|
import {useExpanded} from './useExpanded';
|
|
9
8
|
import {useDropdown} from './useDropdown';
|
|
10
9
|
import {useRouter, navigate} from '../../hooks/useRouter';
|
|
10
|
+
import {useRecordItem} from '../../hooks/useRecordComponent';
|
|
11
|
+
import {MENU_RECORD_KEY} from './useHighlight';
|
|
11
12
|
|
|
12
13
|
export interface MenuItemProps {
|
|
13
14
|
key: Key
|
|
@@ -42,23 +43,23 @@ export class MenuItem extends Component<MenuItemProps, MenuItemEvents> {
|
|
|
42
43
|
public parentMenuItem = inject<MenuItem | null>(MENU_ITEM, null);
|
|
43
44
|
|
|
44
45
|
private expanded = useExpanded(this.rootMenu, this.parentMenu);
|
|
45
|
-
private highlight = useHighlight(this.rootMenu, this.parentMenuItem);
|
|
46
46
|
private dropdown = useDropdown(this.rootMenu, this.parentMenu);
|
|
47
47
|
private router = useRouter();
|
|
48
48
|
|
|
49
49
|
init() {
|
|
50
50
|
provide(MENU_ITEM, this);
|
|
51
|
+
useRecordItem(MENU_RECORD_KEY);
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
@bind
|
|
54
55
|
public onClick(hasSubMenu: Menu, e: MouseEvent) {
|
|
55
|
-
const {disabled, to} = this.get();
|
|
56
|
+
const {disabled, to, key} = this.get();
|
|
56
57
|
if (disabled) return;
|
|
57
58
|
|
|
58
59
|
if (hasSubMenu) {
|
|
59
60
|
this.expanded.toggle();
|
|
60
61
|
} else {
|
|
61
|
-
this.highlight
|
|
62
|
+
this.rootMenu.highlight!.select(key);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
this.trigger('click', e);
|
package/components/menu/item.vdt
CHANGED
|
@@ -10,7 +10,7 @@ import {makeItemStyles, makeTitleStyles} from './styles';
|
|
|
10
10
|
const rootMenu = this.rootMenu;
|
|
11
11
|
const {theme, type, dot: rootDot} = rootMenu.get();
|
|
12
12
|
const {children, key, className, disabled, dot} = this.get();
|
|
13
|
-
const {isHighlighted, isSelected} =
|
|
13
|
+
const {isHighlighted, isSelected} = rootMenu.highlight;
|
|
14
14
|
const {isExpanded: isExpandedKey} = this.expanded;
|
|
15
15
|
const isExpanded = isExpandedKey(key);
|
|
16
16
|
const {
|
|
@@ -23,8 +23,8 @@ const classNameObj = {
|
|
|
23
23
|
[className]: className,
|
|
24
24
|
'k-expanded': isExpanded,
|
|
25
25
|
'k-disabled': disabled,
|
|
26
|
-
'k-active': isSelected(),
|
|
27
|
-
'k-highlighted': isHighlighted(),
|
|
26
|
+
'k-active': isSelected(key),
|
|
27
|
+
'k-highlighted': isHighlighted(key),
|
|
28
28
|
[makeItemStyles()]: true,
|
|
29
29
|
};
|
|
30
30
|
|
package/components/menu/menu.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {Component, TypeDefs, provide, inject, Key} from 'intact';
|
|
2
2
|
import template from './menu.vdt';
|
|
3
|
+
import {useHighlight} from './useHighlight';
|
|
3
4
|
|
|
4
5
|
export interface MenuProps<K extends Key = Key> {
|
|
5
6
|
expandedKeys?: K[]
|
|
@@ -46,6 +47,8 @@ export class Menu<K extends Key = Key> extends Component<MenuProps<K>, MenuEvent
|
|
|
46
47
|
|
|
47
48
|
public rootMenu = inject<Menu | null>(ROOT_MENU, null);
|
|
48
49
|
public parentMenu = inject<Menu | null>(MENU, null);
|
|
50
|
+
public subExpandedKeys?: Set<K>;
|
|
51
|
+
public highlight?: ReturnType<typeof useHighlight>;
|
|
49
52
|
|
|
50
53
|
init() {
|
|
51
54
|
provide(MENU, this);
|
|
@@ -53,6 +56,7 @@ export class Menu<K extends Key = Key> extends Component<MenuProps<K>, MenuEvent
|
|
|
53
56
|
// is root menu or not
|
|
54
57
|
if (!this.rootMenu) {
|
|
55
58
|
provide(ROOT_MENU, this);
|
|
59
|
+
this.highlight = useHighlight();
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
}
|
|
@@ -3,7 +3,7 @@ import type {Menu, MenuItem} from './';
|
|
|
3
3
|
import {inArray, addOrRemove} from '../table/useChecked';
|
|
4
4
|
import {isDropdown} from './useDropdown';
|
|
5
5
|
|
|
6
|
-
export function useExpanded(rootMenu: Menu, parentMenu: Menu
|
|
6
|
+
export function useExpanded(rootMenu: Menu, parentMenu: Menu) {
|
|
7
7
|
const instance = useInstance() as MenuItem;
|
|
8
8
|
|
|
9
9
|
onBeforeUnmount(removeSubExpandedKey);
|
|
@@ -1,52 +1,57 @@
|
|
|
1
|
-
import {useInstance,
|
|
1
|
+
import {useInstance, Key} from 'intact';
|
|
2
2
|
import type {Menu, MenuItem} from './';
|
|
3
|
+
import {useRecordParent} from '../../hooks/useRecordComponent';
|
|
3
4
|
import {inArray} from '../table/useChecked';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
)
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
updateStatus(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
import {useState} from '../../hooks/useState';
|
|
6
|
+
|
|
7
|
+
export const MENU_RECORD_KEY = 'MenuKeys';
|
|
8
|
+
|
|
9
|
+
export function useHighlight() {
|
|
10
|
+
const instance = useInstance() as Menu;
|
|
11
|
+
const menuItems = useRecordParent<MenuItem>(MENU_RECORD_KEY);
|
|
12
|
+
const highlightedKeys = useState<Key[]>([]);
|
|
13
|
+
|
|
14
|
+
instance.watch('selectedKey', updateStatus, {presented: true});
|
|
15
|
+
|
|
16
|
+
function updateStatus(newValue: Key | undefined) {
|
|
17
|
+
for (let i = 0; i < menuItems.length; i++) {
|
|
18
|
+
const menuItem = menuItems[i];
|
|
19
|
+
const key = menuItem.get('key');
|
|
20
|
+
|
|
21
|
+
if (newValue !== key) continue;
|
|
22
|
+
|
|
23
|
+
const items = [];
|
|
24
|
+
let parentItem = menuItem.parentMenuItem;
|
|
25
|
+
while (parentItem) {
|
|
26
|
+
items.push(parentItem);
|
|
27
|
+
parentItem = parentItem.parentMenuItem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const expandedKeys = new Set(instance.get('expandedKeys'));
|
|
31
|
+
highlightedKeys.set(items.map(item => {
|
|
32
|
+
const key = item.get('key');
|
|
33
|
+
expandedKeys.add(key);
|
|
34
|
+
return key;
|
|
35
|
+
}));
|
|
36
|
+
instance.set('expandedKeys', Array.from(expandedKeys))
|
|
37
|
+
|
|
38
|
+
return;
|
|
27
39
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const highlightedKeys = items.map(item => {
|
|
31
|
-
const key = item.get('key');
|
|
32
|
-
expandedKeys.add(key);
|
|
33
|
-
return key;
|
|
34
|
-
});
|
|
35
|
-
rootMenu.highlightedKeys = highlightedKeys;
|
|
36
|
-
rootMenu.set('expandedKeys', Array.from(expandedKeys))
|
|
40
|
+
|
|
41
|
+
highlightedKeys.set([]);
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
function isHighlighted() {
|
|
40
|
-
return inArray(
|
|
44
|
+
function isHighlighted(key: Key) {
|
|
45
|
+
return inArray(highlightedKeys.value, key);
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
function select() {
|
|
44
|
-
|
|
48
|
+
function select(key: Key) {
|
|
49
|
+
instance.set('selectedKey', key);
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
function isSelected() {
|
|
48
|
-
return
|
|
52
|
+
function isSelected(key: Key) {
|
|
53
|
+
return instance.get('selectedKey') === key;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
return {isHighlighted,
|
|
56
|
+
return {isHighlighted, select, isSelected};
|
|
52
57
|
}
|
package/components/portal.ts
CHANGED
|
@@ -100,7 +100,7 @@ export class Portal<T extends PortalProps = PortalProps> extends Component<T> {
|
|
|
100
100
|
}
|
|
101
101
|
} else {
|
|
102
102
|
mountedQueue.push(() => {
|
|
103
|
-
parentDom = this.$lastInput!.dom!.parentElement!;
|
|
103
|
+
const parentDom = this.$lastInput!.dom!.parentElement!;
|
|
104
104
|
this.initContainer(nextProps.container, parentDom, anchor);
|
|
105
105
|
|
|
106
106
|
mount(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 动画效果
|
|
3
|
+
order: 3
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
添加animated属性可显示动画效果。
|
|
7
|
+
|
|
8
|
+
```vdt
|
|
9
|
+
import {Skeleton} from 'kpc';
|
|
10
|
+
|
|
11
|
+
<div>
|
|
12
|
+
<Skeleton loading={this.get('showSkeleton')} avator animated />
|
|
13
|
+
</div>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
interface Props {
|
|
18
|
+
showSkeleton?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default class extends Component<Props> {
|
|
22
|
+
static template = template;
|
|
23
|
+
|
|
24
|
+
static defaults() {
|
|
25
|
+
return {
|
|
26
|
+
showSkeleton: true
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 头像模式
|
|
3
|
+
order: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
avator属性可以用来将组件显示为头像模式。
|
|
7
|
+
|
|
8
|
+
```vdt
|
|
9
|
+
import {Skeleton} from 'kpc';
|
|
10
|
+
|
|
11
|
+
<div>
|
|
12
|
+
<Skeleton loading={this.get('showSkeleton')} avator={true} />
|
|
13
|
+
</div>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
interface Props {
|
|
18
|
+
showSkeleton?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default class extends Component<Props> {
|
|
22
|
+
static template = template;
|
|
23
|
+
|
|
24
|
+
static defaults() {
|
|
25
|
+
return {
|
|
26
|
+
showSkeleton: true
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 基础用法
|
|
3
|
+
order: 0
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
最简单的骨架屏用法,通过loading属性来控制骨架屏的显示或隐藏效果。也可以使用Spin来代替,但是在某些场景下能提供比Spin更好的视觉效果和用户体验。
|
|
7
|
+
|
|
8
|
+
```vdt
|
|
9
|
+
import {Skeleton} from 'kpc';
|
|
10
|
+
|
|
11
|
+
<div>
|
|
12
|
+
<Skeleton loading={this.get('showSkeleton')} />
|
|
13
|
+
</div>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
interface Props {
|
|
18
|
+
showSkeleton?: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default class extends Component<Props> {
|
|
22
|
+
static template = template;
|
|
23
|
+
|
|
24
|
+
static defaults() {
|
|
25
|
+
return {
|
|
26
|
+
showSkeleton: true
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 自定义样式
|
|
3
|
+
order: 4
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
我们为SkeletonItem提供了`type`属性,默认具有"text" | "avator" | "image" | "button" | "input"几种类型。他们分别模拟了文本、头像、图片、按钮、输入框几种元素的外观。在提供的默认样式不能满足需求的时候,我们可以通过自定义模板来实现预期的效果。
|
|
7
|
+
|
|
8
|
+
```vdt
|
|
9
|
+
import {Skeleton, SkeletonItem} from 'kpc';
|
|
10
|
+
|
|
11
|
+
<div>
|
|
12
|
+
<Skeleton loading={this.get('showSkeleton')} avator animated>
|
|
13
|
+
<SkeletonItem type="image"></SkeletonItem>
|
|
14
|
+
<div style="display: flex; justify-content: space-between; width: 200px; margin-top: 20px;">
|
|
15
|
+
<div>
|
|
16
|
+
<SkeletonItem type="button" style="height: 16px;"></SkeletonItem>
|
|
17
|
+
<SkeletonItem type="button" style="height: 16px; margin-top: 8px;"></SkeletonItem>
|
|
18
|
+
</div>
|
|
19
|
+
<SkeletonItem type="button"></SkeletonItem>
|
|
20
|
+
</div>
|
|
21
|
+
</Skeleton>
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
interface Props {
|
|
27
|
+
showSkeleton?: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default class extends Component<Props> {
|
|
31
|
+
static template = template;
|
|
32
|
+
|
|
33
|
+
static defaults() {
|
|
34
|
+
return {
|
|
35
|
+
showSkeleton: true
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 控制行数
|
|
3
|
+
order: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
可以根据需要,来控制骨架屏显示的行数,默认为2行。
|
|
7
|
+
|
|
8
|
+
```vdt
|
|
9
|
+
import {Skeleton} from 'kpc';
|
|
10
|
+
|
|
11
|
+
<div>
|
|
12
|
+
<Skeleton loading={this.get('showSkeleton')} rows={this.get('rows')} />
|
|
13
|
+
</div>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
interface Props {
|
|
18
|
+
showSkeleton?: boolean
|
|
19
|
+
rows?: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default class extends Component<Props> {
|
|
23
|
+
static template = template;
|
|
24
|
+
|
|
25
|
+
static defaults() {
|
|
26
|
+
return {
|
|
27
|
+
showSkeleton: true,
|
|
28
|
+
rows: 4
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 骨架屏
|
|
3
|
+
category: 组件
|
|
4
|
+
order: 2
|
|
5
|
+
sidebar: doc
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 属性
|
|
9
|
+
|
|
10
|
+
## Skeleton
|
|
11
|
+
|
|
12
|
+
| 属性 | 说明 | 类型 | 默认值 |
|
|
13
|
+
| --- | --- | --- | --- |
|
|
14
|
+
| loading | 是否显示骨架屏 | `boolean` | `false` |
|
|
15
|
+
| rows | 完整长度的行数 | `number` | `2` |
|
|
16
|
+
| animated | 是否显示动画 | `boolean` | `false` |
|
|
17
|
+
| avator | 是否显示为头像模式 | `boolean` | `false` |
|
|
18
|
+
| size | 骨架屏尺寸 | `"default"` | `"small"` | `"mini"` | `"default"` |
|
|
19
|
+
|
|
20
|
+
## SkeletonItem
|
|
21
|
+
|
|
22
|
+
| 属性 | 说明 | 类型 | 默认值 |
|
|
23
|
+
| --- | --- | --- | --- |
|
|
24
|
+
| type | 骨架屏元素类型 | `"text"` | `"avator"` | `"image"` | `"button"` | `"input"` | `"text"` |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {Component, TypeDefs} from 'intact';
|
|
2
|
+
import template from './item.vdt';
|
|
3
|
+
|
|
4
|
+
type ItemType = 'text' | 'avator' | 'image' | 'button' | 'input';
|
|
5
|
+
|
|
6
|
+
export const ItemTypeMap: ItemType[] = ['text', 'avator', 'image', 'button', 'input'];
|
|
7
|
+
|
|
8
|
+
export interface SkeletonItemProps {
|
|
9
|
+
type?: ItemType,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SkeletonItemEvents {}
|
|
13
|
+
|
|
14
|
+
export interface SkeletonItemBlocks {}
|
|
15
|
+
|
|
16
|
+
const typeDefs: Required<TypeDefs<SkeletonItemProps>> = {
|
|
17
|
+
type: ItemTypeMap
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const defaults = (): Partial<SkeletonItemProps> => ({
|
|
21
|
+
type: 'text'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export class SkeletonItem extends Component<SkeletonItemProps, SkeletonItemEvents, SkeletonItemBlocks> {
|
|
25
|
+
static template = template;
|
|
26
|
+
static typeDefs = typeDefs;
|
|
27
|
+
static defaults = defaults;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|