@king-design/intact 2.0.0 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +20 -118
  2. package/components/cascader/index.spec.ts +59 -0
  3. package/components/cascader/index.vdt +4 -4
  4. package/components/cascader/useLabel.ts +9 -9
  5. package/components/datepicker/index.vdt +7 -6
  6. package/components/dropdown/dropdown.ts +7 -6
  7. package/components/form/index.spec.ts +1 -1
  8. package/components/menu/demos/collapse.md +3 -1
  9. package/components/menu/index.spec.ts +10 -4
  10. package/components/menu/item.ts +5 -4
  11. package/components/menu/item.vdt +3 -3
  12. package/components/menu/menu.ts +4 -0
  13. package/components/menu/useExpanded.ts +1 -1
  14. package/components/menu/useHighlight.ts +45 -40
  15. package/components/portal.ts +1 -1
  16. package/components/skeleton/demos/animate.md +30 -0
  17. package/components/skeleton/demos/avator.md +30 -0
  18. package/components/skeleton/demos/basic.md +30 -0
  19. package/components/skeleton/demos/custom.md +39 -0
  20. package/components/skeleton/demos/rows.md +32 -0
  21. package/components/skeleton/index.md +24 -0
  22. package/components/skeleton/index.ts +2 -0
  23. package/components/skeleton/item.ts +30 -0
  24. package/components/skeleton/item.vdt +28 -0
  25. package/components/skeleton/skeleton.ts +33 -0
  26. package/components/skeleton/skeleton.vdt +32 -0
  27. package/components/skeleton/style.ts +105 -0
  28. package/components/tooltip/index.spec.ts +6 -1
  29. package/components/transfer/styles.ts +2 -8
  30. package/components/tree/useFilter.ts +1 -2
  31. package/es/components/cascader/index.spec.js +88 -0
  32. package/es/components/cascader/index.vdt.js +4 -4
  33. package/es/components/cascader/useLabel.js +8 -12
  34. package/es/components/datepicker/index.vdt.js +10 -5
  35. package/es/components/diagram/index.d.ts +1 -1
  36. package/es/components/dropdown/dropdown.js +8 -7
  37. package/es/components/form/index.spec.js +2 -4
  38. package/es/components/menu/index.spec.js +13 -6
  39. package/es/components/menu/item.d.ts +0 -1
  40. package/es/components/menu/item.js +6 -4
  41. package/es/components/menu/item.vdt.js +4 -4
  42. package/es/components/menu/menu.d.ts +3 -0
  43. package/es/components/menu/menu.js +4 -0
  44. package/es/components/menu/useExpanded.d.ts +1 -4
  45. package/es/components/menu/useHighlight.d.ts +5 -8
  46. package/es/components/menu/useHighlight.js +44 -33
  47. package/es/components/portal.js +1 -1
  48. package/es/components/skeleton/index.d.ts +2 -0
  49. package/es/components/skeleton/index.js +2 -0
  50. package/es/components/skeleton/item.d.ts +16 -0
  51. package/es/components/skeleton/item.js +26 -0
  52. package/es/components/skeleton/item.vdt.js +35 -0
  53. package/es/components/skeleton/skeleton.d.ts +17 -0
  54. package/es/components/skeleton/skeleton.js +30 -0
  55. package/es/components/skeleton/skeleton.vdt.js +37 -0
  56. package/es/components/skeleton/style.d.ts +6 -0
  57. package/es/components/skeleton/style.js +35 -0
  58. package/es/components/steps/context.d.ts +2 -2
  59. package/es/components/tooltip/index.spec.js +4 -1
  60. package/es/components/transfer/styles.js +2 -6
  61. package/es/components/tree/useFilter.js +1 -2
  62. package/es/i18n/en-US.d.ts +1 -0
  63. package/es/i18n/en-US.js +1 -0
  64. package/es/index.d.ts +3 -2
  65. package/es/index.js +3 -2
  66. package/es/packages/kpc-react/__tests__/components/form.spec.d.ts +1 -0
  67. package/es/packages/kpc-react/__tests__/components/form.spec.js +46 -0
  68. package/es/site/data/components/menu/demos/collapse/index.js +1 -0
  69. package/es/site/data/components/menu/demos/collapse/react.d.ts +1 -1
  70. package/es/site/data/components/menu/demos/collapse/react.js +7 -0
  71. package/es/site/data/components/menu/demos/size/react.d.ts +1 -1
  72. package/es/site/data/components/skeleton/demos/animate/index.d.ts +11 -0
  73. package/es/site/data/components/skeleton/demos/animate/index.js +23 -0
  74. package/es/site/data/components/skeleton/demos/animate/react.d.ts +11 -0
  75. package/es/site/data/components/skeleton/demos/animate/react.js +38 -0
  76. package/es/site/data/components/skeleton/demos/avator/index.d.ts +11 -0
  77. package/es/site/data/components/skeleton/demos/avator/index.js +23 -0
  78. package/es/site/data/components/skeleton/demos/avator/react.d.ts +11 -0
  79. package/es/site/data/components/skeleton/demos/avator/react.js +37 -0
  80. package/es/site/data/components/skeleton/demos/basic/index.d.ts +11 -0
  81. package/es/site/data/components/skeleton/demos/basic/index.js +23 -0
  82. package/es/site/data/components/skeleton/demos/basic/react.d.ts +11 -0
  83. package/es/site/data/components/skeleton/demos/basic/react.js +36 -0
  84. package/es/site/data/components/skeleton/demos/custom/index.d.ts +11 -0
  85. package/es/site/data/components/skeleton/demos/custom/index.js +23 -0
  86. package/es/site/data/components/skeleton/demos/custom/react.d.ts +11 -0
  87. package/es/site/data/components/skeleton/demos/custom/react.js +60 -0
  88. package/es/site/data/components/skeleton/demos/rows/index.d.ts +13 -0
  89. package/es/site/data/components/skeleton/demos/rows/index.js +24 -0
  90. package/es/site/data/components/skeleton/demos/rows/react.d.ts +13 -0
  91. package/es/site/data/components/skeleton/demos/rows/react.js +38 -0
  92. package/es/site/data/components/skeleton/index.d.ts +57 -0
  93. package/es/site/data/components/skeleton/index.js +42 -0
  94. package/es/site/src/client.js +4 -1
  95. package/es/site/src/components/footer/styles.js +1 -1
  96. package/es/site/src/pages/colorProcess/index.d.ts +21 -0
  97. package/es/site/src/pages/colorProcess/index.js +79 -0
  98. package/es/site/src/pages/colorProcess/style.d.ts +3 -0
  99. package/es/site/src/pages/colorProcess/style.js +53 -0
  100. package/es/site/src/pages/font/index.d.ts +12 -0
  101. package/es/site/src/pages/font/index.js +22 -0
  102. package/es/site/src/pages/font/styles.d.ts +1 -0
  103. package/es/site/src/pages/font/styles.js +9 -0
  104. package/es/site/src/pages/iframe/colorProcess/styles.js +2 -2
  105. package/es/site/src/pages/index/BestPractice/styles.js +1 -1
  106. package/es/site/src/pages/index/ColorProcess/styles.js +2 -2
  107. package/es/site/src/pages/index/KingVersion/styles.js +1 -1
  108. package/es/site/src/pages/index/NewFunction/index.d.ts +2 -0
  109. package/es/site/src/pages/index/NewFunction/index.js +8 -2
  110. package/es/site/src/pages/index/NewFunction/styles.js +1 -1
  111. package/es/site/src/pages/index/styles.js +2 -1
  112. package/es/site/src/pages/layout.d.ts +1 -0
  113. package/es/site/src/pages/layout.js +9 -1
  114. package/es/site/src/pages/resource/index.d.ts +1 -0
  115. package/es/site/src/pages/resource/index.js +7 -4
  116. package/es/site/src/pages/solution/index.js +1 -2
  117. package/es/site/src/pages/styles.js +2 -2
  118. package/es/site/src/router/index.js +75 -5
  119. package/i18n/en-US.ts +1 -0
  120. package/index.ts +3 -2
  121. package/package.json +5 -4
  122. package/es/components/cascader/index.d.ts +0 -34
  123. package/es/components/datepicker/index.d.ts +0 -63
  124. package/es/components/select/select.d.ts +0 -33
  125. package/es/components/timepicker/panelPicker.d.ts +0 -54
  126. package/es/components/treeSelect/index.d.ts +0 -27
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
1
  <div align="center">
2
2
 
3
- <a href="https://ksc-fe.github.io/kpc/" rel="nofollow">
4
- <img src="/site/src/imgs/logo.png" alt="LOGO" width="150">
3
+ <a href="https://design.ksyun.com" rel="nofollow">
4
+ <img src="/site/src/imgs/header_logo_x2.png" alt="LOGO" />
5
5
  </a>
6
6
 
7
7
  <p></p>
8
8
 
9
9
  [![Build Status](https://github.com/ksc-fe/kpc/workflows/Node.js%20CI/badge.svg?branch=master)](https://github.com/ksc-fe/kpc/actions?query=workflow%3A%22Node.js+CI%22)
10
10
  [![Codecov](https://codecov.io/gh/ksc-fe/kpc/branch/master/graphs/badge.svg)](https://codecov.io/gh/ksc-fe/kpc/branch/master)
11
- [![gzip size: js](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/kpc/dist/kpc.min.js?compression=gzip&label=gzip%20size:%20js)](https://cdn.jsdelivr.net/npm/kpc/dist/)
12
- [![gzip size: css](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/kpc/dist/kpc.css?compression=gzip&label=gzip%20size:%20css)](https://cdn.jsdelivr.net/npm/kpc/dist/)
11
+ [![npm](https://img.shields.io/npm/v/@king-design/vue.svg)](https://www.npmjs.com/package/@king-design/vue)
13
12
 
14
- [![npm](https://img.shields.io/npm/dm/kpc.svg)](https://www.npmjs.com/package/kpc)
15
- [![npm](https://img.shields.io/npm/v/kpc.svg)](https://www.npmjs.com/package/kpc)
13
+ [![npm](https://img.shields.io/npm/dm/@king-design/react.svg?label=react%20download)](https://www.npmjs.com/package/@king-design/react)
14
+ [![npm](https://img.shields.io/npm/dm/@king-design/vue.svg?label=vue3%20download)](https://www.npmjs.com/package/@king-design/vue)
15
+ [![npm](https://img.shields.io/npm/dm/@king-design/vue-legacy.svg?label=vue2%20download)](https://www.npmjs.com/package/@king-design/vue-legacy)
16
16
 
17
17
  </div>
18
18
 
@@ -20,11 +20,11 @@ English | [简体中文](./README-zh_CN.md)
20
20
 
21
21
  ## Features
22
22
 
23
- * Support multiple frameworks: [Intact][1] / [Vue][2] / [React][3] / [Angular][4].
24
- * Complete custom theme system.
25
- * 360° locate popup layer.
23
+ * Support multiple frameworks: [Intact][1] / [Vue][2] / [React][3].
24
+ * Support TypeScript.
25
+ * Change theme on runtime.
26
26
  * Declarative form validation.
27
- * Excellent [documents](https://ksc-fe.github.io/kpc/) and design
27
+ * Excellent [documents](https://design.ksyun.com) and design
28
28
  * 90% coverage unit tests.
29
29
 
30
30
  ## Browsers Support
@@ -38,7 +38,11 @@ English | [简体中文](./README-zh_CN.md)
38
38
  ### Installation
39
39
 
40
40
  ```shell
41
- npm install kpc-vue --save
41
+ # Vue3
42
+ npm install @king-design/vue --save
43
+
44
+ # Vue2
45
+ npm install @king-desing/vue-legacy --save
42
46
  ```
43
47
 
44
48
  ### Usage
@@ -48,7 +52,7 @@ npm install kpc-vue --save
48
52
  <Button>Hello</Button>
49
53
  </template>
50
54
  <script>
51
- import {Button} from 'kpc-vue';
55
+ import {Button} from '@king-design/vue';
52
56
 
53
57
  export default {
54
58
  components: {
@@ -63,114 +67,16 @@ export default {
63
67
  ### Installation
64
68
 
65
69
  ```shell
66
- npm install kpc-react --save
70
+ npm install @king-design/react--save
67
71
  ```
68
72
 
69
73
  ### Usage
70
74
 
71
75
  ```jsx
72
- import React from 'react';
73
- import {Button} from 'kpc-react';
74
-
75
- class App extends React.Component {
76
- render() {
77
- return <Button>Hello</Button>
78
- }
79
- }
80
- ```
81
-
82
- ## Intact
83
-
84
- ### Installation
85
-
86
- ```shell
87
- npm install kpc --save
88
- ```
89
-
90
- ### Usage
91
-
92
- ```js
93
- import {Button} from 'kpc';
94
-
95
- <Button>Hello</Button>
96
- ```
97
-
98
- ## Angular
99
-
100
- Read [more][5]
76
+ import {Button} from '@king-design/react';
101
77
 
102
- ### Installation
103
-
104
- ```shell
105
- npm install kpc-angular -S
106
- ```
107
-
108
- ### Configure `webpack.config.js`
109
-
110
- You need use `@angular-builders/custom-webapck` to configure webpack, if your project initialized by Angular CLI.
111
-
112
- ```js
113
- const path = require('path');
114
-
115
- module.exports = function(config) {
116
- config.module.rules.find(rule => {
117
- if (rule.test.toString() === '/\\.css$/') {
118
- rule.exclude.push(path.resolve(__dirname, 'node_modules/kpc-angular'));
119
- return true;
120
- }
121
- });
122
-
123
- return config;
124
- };
125
- ```
126
-
127
- ### Usage
128
-
129
- `src/app/app.module.ts`
130
-
131
- ```ts
132
- import { KpcBrowserModule, KpcModule } from 'kpc-angular';
133
- import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
134
-
135
- import { AppRoutingModule } from './app-routing.module';
136
- import { AppComponent } from './app.component';
137
-
138
- @NgModule({
139
- declarations: [
140
- AppComponent
141
- ],
142
- imports: [
143
- KpcBrowserModule,
144
- AppRoutingModule,
145
- KpcModule,
146
- ],
147
- providers: [],
148
- bootstrap: [AppComponent],
149
- schemas: [CUSTOM_ELEMENTS_SCHEMA]
150
- })
151
- export class AppModule { }
152
- ```
153
-
154
- ```ts
155
- import { Component, ViewEncapsulation } from '@angular/core';
156
- import { MessageComponent } from 'kpc-angular';
157
-
158
- @Component({
159
- selector: 'app-root',
160
- template: `
161
- <k-button type="primary" (click)="onClick()">Hello World</k-button>
162
- `,
163
- style: `
164
- .k-button {
165
- margin: 10px;
166
- }
167
- `,
168
- encapsulation: ViewEncapsulation.None,
169
- })
170
- export class AppComponent {
171
- onClick() {
172
- MessageComponent.success('Welcome to kpc world!');
173
- }
78
+ function App() {
79
+ return <Button>Hello</Button>
174
80
  }
175
81
  ```
176
82
 
@@ -187,10 +93,6 @@ Welcome to join us by QQ. Group Number: 529739732
187
93
 
188
94
  * [KPC Document](https://design.ksyun.com)
189
95
  * [Intact MVVM Framework][1]
190
- * [Vdt Template Engine](http://javey.github.io/vdt.js/)
191
- * [Intact-Vue Compatibility Layer](https://github.com/Javey/intact-vue)
192
- * [Intact-React Compatibility Layer](https://github.com/ksc-fe/intact-react)
193
- * [Intact-Angular Compatibility Layer](https://github.com/ksc-fe/intact-angular)
194
96
 
195
97
  ## Develop
196
98
 
@@ -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 (value.includes(item.value)) {
22
+ if (item.value === value[level]) {
21
23
  labels.push(item.label);
22
- if (labels.length === length) {
23
- return;
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
  }
@@ -76,12 +76,13 @@ const generatePanel = (flag) => {
76
76
  <b:base-menu>
77
77
  <DropdownMenu class={classNameObj}>
78
78
  <div class="k-datepicker-shortcuts" v-if={shortcuts && shortcuts.length}>
79
- <div v-for={shortcuts}
80
- class="k-datepicker-shortcut"
81
- ev-click={linkEvent($value, this.setByShortcut)}
82
- >
83
- {isFunction($value.label) ? $value.label() : $value.label}
84
- </div>
79
+ {shortcuts.map($value => {
80
+ const label = isFunction($value.label) ? $value.label() : $value.label;
81
+ return <div class="k-datepicker-shortcut c-ellipsis"
82
+ title={label}
83
+ ev-click={linkEvent($value, this.setByShortcut)}
84
+ >{label}</div>
85
+ })}
85
86
  </div>
86
87
  <div class="k-datepicker-wrapper">
87
88
  <div class="k-datepicker-calendars">
@@ -244,11 +244,15 @@ 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
- if ((this as any).$isReact || (this as any).$isVueNext) {
248
- const vnode = props.vnode;
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;
254
+ if (!_props) return props;
255
+
252
256
  return {
253
257
  vnode,
254
258
  'ev-click': _props.onClick,
@@ -258,9 +262,6 @@ export class Dropdown<
258
262
  className: _props.className || _props.class /* vue-next */,
259
263
  };
260
264
  } else if ((this as any).$isVue) {
261
- const vnode = props.vnode;
262
- if (!vnode) return props;
263
-
264
265
  const data = vnode.data;
265
266
  const on = data && data.on || EMPTY_OBJ;
266
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
- const menu = instance.refs.__test as Menu;
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(menu.get('selectedKey')).to.eql('1');
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(menu.get('selectedKey')).to.eql('1');
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(menu.get('selectedKey')).to.eql('3-1');
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 () => {
@@ -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.select();
62
+ this.rootMenu.highlight!.select(key);
62
63
  }
63
64
 
64
65
  this.trigger('click', e);
@@ -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} = this.highlight;
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
 
@@ -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 & {subExpandedKeys?: Set<Key>}) {
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, createRef, onMounted, onUpdated, onUnmounted, Key} from 'intact';
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
- // import {isEqualArray} from '../utils';
5
-
6
- export function useHighlight(
7
- rootMenu: Menu & {highlightedKeys?: Key[]},
8
- parentMenuItem: MenuItem | null
9
- ) {
10
- const instance = useInstance() as MenuItem;
11
-
12
- // we can not watch selectedKey on before initializing rootMenu
13
- // because rootMenu has initialized
14
- // so call updateStatus here
15
- updateStatus(rootMenu.get('selectedKey'));
16
- rootMenu.watch('selectedKey', updateStatus);
17
-
18
- function updateStatus(v: Key | undefined) {
19
- const {key} = instance.get();
20
- if (v !== key) return;
21
-
22
- const items = [];
23
- let parentItem = parentMenuItem;
24
- while (parentItem) {
25
- items.push(parentItem);
26
- parentItem = parentItem.parentMenuItem;
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
- const expandedKeys = new Set(rootMenu.get('expandedKeys'));
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(rootMenu.highlightedKeys, instance.get('key'));
44
+ function isHighlighted(key: Key) {
45
+ return inArray(highlightedKeys.value, key);
41
46
  }
42
47
 
43
- function select() {
44
- rootMenu.set('selectedKey', instance.get('key'));
48
+ function select(key: Key) {
49
+ instance.set('selectedKey', key);
45
50
  }
46
51
 
47
- function isSelected() {
48
- return rootMenu.get('selectedKey') === instance.get('key');
52
+ function isSelected(key: Key) {
53
+ return instance.get('selectedKey') === key;
49
54
  }
50
55
 
51
- return {isHighlighted, updateStatus, select, isSelected};
56
+ return {isHighlighted, select, isSelected};
52
57
  }
@@ -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(