wok-ui-ext 0.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.
Files changed (235) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +75 -0
  3. package/README.md +75 -0
  4. package/dist/alert/index.d.ts +10 -0
  5. package/dist/alert/index.js +48 -0
  6. package/dist/alert/style.css +116 -0
  7. package/dist/avatar/index.d.ts +9 -0
  8. package/dist/avatar/index.js +30 -0
  9. package/dist/avatar/style.css +32 -0
  10. package/dist/badge/index.d.ts +32 -0
  11. package/dist/badge/index.js +61 -0
  12. package/dist/badge/style.css +68 -0
  13. package/dist/breadcrumb/index.d.ts +25 -0
  14. package/dist/breadcrumb/index.js +47 -0
  15. package/dist/breadcrumb/style.css +35 -0
  16. package/dist/button/index.d.ts +34 -0
  17. package/dist/button/index.js +57 -0
  18. package/dist/button/style.css +133 -0
  19. package/dist/card/index.d.ts +25 -0
  20. package/dist/card/index.js +29 -0
  21. package/dist/card/style.css +23 -0
  22. package/dist/collapse/index.d.ts +89 -0
  23. package/dist/collapse/index.js +213 -0
  24. package/dist/collapse/style.css +76 -0
  25. package/dist/context-menu/context-menu.d.ts +113 -0
  26. package/dist/context-menu/context-menu.js +150 -0
  27. package/dist/context-menu/index.d.ts +30 -0
  28. package/dist/context-menu/index.js +42 -0
  29. package/dist/context-menu/style.css +46 -0
  30. package/dist/date-picker/calendar-panel.d.ts +44 -0
  31. package/dist/date-picker/calendar-panel.js +180 -0
  32. package/dist/date-picker/date-picker.d.ts +29 -0
  33. package/dist/date-picker/date-picker.js +81 -0
  34. package/dist/date-picker/date-utils.d.ts +63 -0
  35. package/dist/date-picker/date-utils.js +130 -0
  36. package/dist/date-picker/index.d.ts +7 -0
  37. package/dist/date-picker/index.js +5 -0
  38. package/dist/date-picker/layer.d.ts +19 -0
  39. package/dist/date-picker/layer.js +36 -0
  40. package/dist/date-picker/range-picker.d.ts +30 -0
  41. package/dist/date-picker/range-picker.js +117 -0
  42. package/dist/date-picker/style.css +161 -0
  43. package/dist/description-list/index.d.ts +37 -0
  44. package/dist/description-list/index.js +145 -0
  45. package/dist/description-list/style.css +63 -0
  46. package/dist/divider/index.d.ts +29 -0
  47. package/dist/divider/index.js +29 -0
  48. package/dist/divider/style.css +50 -0
  49. package/dist/drawer/index.d.ts +51 -0
  50. package/dist/drawer/index.js +183 -0
  51. package/dist/drawer/style.css +100 -0
  52. package/dist/dropdown/index.d.ts +38 -0
  53. package/dist/dropdown/index.js +97 -0
  54. package/dist/dropdown/style.css +39 -0
  55. package/dist/empty/index.d.ts +11 -0
  56. package/dist/empty/index.js +20 -0
  57. package/dist/empty/style.css +19 -0
  58. package/dist/floating-layer/index.d.ts +109 -0
  59. package/dist/floating-layer/index.js +337 -0
  60. package/dist/floating-layer/style.css +5 -0
  61. package/dist/form/form-item/index.d.ts +26 -0
  62. package/dist/form/form-item/index.js +21 -0
  63. package/dist/form/form-item/style.css +33 -0
  64. package/dist/form/form-modal/index.d.ts +18 -0
  65. package/dist/form/form-modal/index.js +38 -0
  66. package/dist/form/form.d.ts +21 -0
  67. package/dist/form/form.js +28 -0
  68. package/dist/form/index.d.ts +4 -0
  69. package/dist/form/index.js +4 -0
  70. package/dist/form/select/index.d.ts +48 -0
  71. package/dist/form/select/index.js +94 -0
  72. package/dist/form/select/style.css +29 -0
  73. package/dist/global.css +71 -0
  74. package/dist/i18n/de-DE.d.ts +2 -0
  75. package/dist/i18n/de-DE.js +36 -0
  76. package/dist/i18n/en-US.d.ts +2 -0
  77. package/dist/i18n/en-US.js +36 -0
  78. package/dist/i18n/es-ES.d.ts +2 -0
  79. package/dist/i18n/es-ES.js +36 -0
  80. package/dist/i18n/fr-FR.d.ts +2 -0
  81. package/dist/i18n/fr-FR.js +36 -0
  82. package/dist/i18n/index.d.ts +12 -0
  83. package/dist/i18n/index.js +39 -0
  84. package/dist/i18n/ja-JP.d.ts +2 -0
  85. package/dist/i18n/ja-JP.js +36 -0
  86. package/dist/i18n/ko-KR.d.ts +2 -0
  87. package/dist/i18n/ko-KR.js +36 -0
  88. package/dist/i18n/messages.d.ts +40 -0
  89. package/dist/i18n/messages.js +1 -0
  90. package/dist/i18n/wok-ui/de-DE.d.ts +2 -0
  91. package/dist/i18n/wok-ui/de-DE.js +20 -0
  92. package/dist/i18n/wok-ui/es-ES.d.ts +2 -0
  93. package/dist/i18n/wok-ui/es-ES.js +20 -0
  94. package/dist/i18n/wok-ui/fr-FR.d.ts +2 -0
  95. package/dist/i18n/wok-ui/fr-FR.js +20 -0
  96. package/dist/i18n/wok-ui/ja-JP.d.ts +2 -0
  97. package/dist/i18n/wok-ui/ja-JP.js +20 -0
  98. package/dist/i18n/wok-ui/ko-KR.d.ts +2 -0
  99. package/dist/i18n/wok-ui/ko-KR.js +20 -0
  100. package/dist/i18n/wok-ui/zh-TW.d.ts +2 -0
  101. package/dist/i18n/wok-ui/zh-TW.js +20 -0
  102. package/dist/i18n/zh-CN.d.ts +2 -0
  103. package/dist/i18n/zh-CN.js +36 -0
  104. package/dist/i18n/zh-TW.d.ts +2 -0
  105. package/dist/i18n/zh-TW.js +36 -0
  106. package/dist/icons.d.ts +88 -0
  107. package/dist/icons.js +176 -0
  108. package/dist/image/index.d.ts +38 -0
  109. package/dist/image/index.js +97 -0
  110. package/dist/image/style.css +72 -0
  111. package/dist/image-preview/index.d.ts +26 -0
  112. package/dist/image-preview/index.js +134 -0
  113. package/dist/image-preview/style.css +96 -0
  114. package/dist/index.d.ts +46 -0
  115. package/dist/index.js +45 -0
  116. package/dist/list/index.d.ts +32 -0
  117. package/dist/list/index.js +42 -0
  118. package/dist/list/list-item.d.ts +27 -0
  119. package/dist/list/list-item.js +51 -0
  120. package/dist/list/style.css +20 -0
  121. package/dist/loading/index.d.ts +10 -0
  122. package/dist/loading/index.js +46 -0
  123. package/dist/loading/style.css +48 -0
  124. package/dist/menu/index.d.ts +38 -0
  125. package/dist/menu/index.js +62 -0
  126. package/dist/menu/leaf-item.d.ts +12 -0
  127. package/dist/menu/leaf-item.js +41 -0
  128. package/dist/menu/style.css +117 -0
  129. package/dist/menu/sub-menu.d.ts +21 -0
  130. package/dist/menu/sub-menu.js +85 -0
  131. package/dist/menu/types.d.ts +36 -0
  132. package/dist/menu/types.js +1 -0
  133. package/dist/menu/utils.d.ts +11 -0
  134. package/dist/menu/utils.js +24 -0
  135. package/dist/modal/index.d.ts +23 -0
  136. package/dist/modal/index.js +79 -0
  137. package/dist/modal/modal.d.ts +76 -0
  138. package/dist/modal/modal.js +188 -0
  139. package/dist/modal/style.css +90 -0
  140. package/dist/pagination/index.d.ts +31 -0
  141. package/dist/pagination/index.js +215 -0
  142. package/dist/pagination/style.css +50 -0
  143. package/dist/popconfirm/api.d.ts +43 -0
  144. package/dist/popconfirm/api.js +77 -0
  145. package/dist/popconfirm/component.d.ts +47 -0
  146. package/dist/popconfirm/component.js +48 -0
  147. package/dist/popconfirm/index.d.ts +3 -0
  148. package/dist/popconfirm/index.js +3 -0
  149. package/dist/popconfirm/style.css +22 -0
  150. package/dist/popover/api.d.ts +36 -0
  151. package/dist/popover/api.js +61 -0
  152. package/dist/popover/component.d.ts +38 -0
  153. package/dist/popover/component.js +51 -0
  154. package/dist/popover/index.d.ts +3 -0
  155. package/dist/popover/index.js +3 -0
  156. package/dist/popover/style.css +102 -0
  157. package/dist/progress/index.d.ts +34 -0
  158. package/dist/progress/index.js +70 -0
  159. package/dist/progress/style.css +37 -0
  160. package/dist/quick-input/index.d.ts +2 -0
  161. package/dist/quick-input/index.js +2 -0
  162. package/dist/quick-input/number.d.ts +35 -0
  163. package/dist/quick-input/number.js +68 -0
  164. package/dist/quick-input/text.d.ts +20 -0
  165. package/dist/quick-input/text.js +61 -0
  166. package/dist/result/index.d.ts +39 -0
  167. package/dist/result/index.js +71 -0
  168. package/dist/result/style.css +41 -0
  169. package/dist/search-box/index.d.ts +26 -0
  170. package/dist/search-box/index.js +60 -0
  171. package/dist/search-box/style.css +22 -0
  172. package/dist/segmented/index.d.ts +42 -0
  173. package/dist/segmented/index.js +61 -0
  174. package/dist/segmented/style.css +28 -0
  175. package/dist/skeleton/index.d.ts +22 -0
  176. package/dist/skeleton/index.js +68 -0
  177. package/dist/skeleton/style.css +31 -0
  178. package/dist/steps/index.d.ts +46 -0
  179. package/dist/steps/index.js +95 -0
  180. package/dist/steps/style.css +181 -0
  181. package/dist/switch/index.d.ts +32 -0
  182. package/dist/switch/index.js +74 -0
  183. package/dist/switch/style.css +52 -0
  184. package/dist/table/body.d.ts +21 -0
  185. package/dist/table/body.js +35 -0
  186. package/dist/table/column.d.ts +78 -0
  187. package/dist/table/column.js +113 -0
  188. package/dist/table/header.d.ts +13 -0
  189. package/dist/table/header.js +15 -0
  190. package/dist/table/index.d.ts +41 -0
  191. package/dist/table/index.js +84 -0
  192. package/dist/table/row.d.ts +25 -0
  193. package/dist/table/row.js +74 -0
  194. package/dist/table/style.css +98 -0
  195. package/dist/tabs/index.d.ts +49 -0
  196. package/dist/tabs/index.js +76 -0
  197. package/dist/tabs/style.css +41 -0
  198. package/dist/tag/index.d.ts +53 -0
  199. package/dist/tag/index.js +100 -0
  200. package/dist/tag/style.css +134 -0
  201. package/dist/text/index.d.ts +104 -0
  202. package/dist/text/index.js +143 -0
  203. package/dist/text/style.css +113 -0
  204. package/dist/theme/index.d.ts +14 -0
  205. package/dist/theme/index.js +94 -0
  206. package/dist/theme/themes.d.ts +3 -0
  207. package/dist/theme/themes.js +323 -0
  208. package/dist/theme/types.d.ts +58 -0
  209. package/dist/theme/types.js +1 -0
  210. package/dist/timeline/index.d.ts +28 -0
  211. package/dist/timeline/index.js +35 -0
  212. package/dist/timeline/style.css +53 -0
  213. package/dist/toast/index.d.ts +53 -0
  214. package/dist/toast/index.js +131 -0
  215. package/dist/toast/style.css +76 -0
  216. package/dist/tooltip/api.d.ts +44 -0
  217. package/dist/tooltip/api.js +103 -0
  218. package/dist/tooltip/component.d.ts +28 -0
  219. package/dist/tooltip/component.js +35 -0
  220. package/dist/tooltip/index.d.ts +3 -0
  221. package/dist/tooltip/index.js +3 -0
  222. package/dist/tooltip/style.css +46 -0
  223. package/dist/tree/dragging-img.d.ts +13 -0
  224. package/dist/tree/dragging-img.js +23 -0
  225. package/dist/tree/index.d.ts +180 -0
  226. package/dist/tree/index.js +385 -0
  227. package/dist/tree/node-info.d.ts +63 -0
  228. package/dist/tree/node-info.js +128 -0
  229. package/dist/tree/node.d.ts +132 -0
  230. package/dist/tree/node.js +264 -0
  231. package/dist/tree/style.css +99 -0
  232. package/dist/upload/index.d.ts +48 -0
  233. package/dist/upload/index.js +141 -0
  234. package/dist/upload/style.css +41 -0
  235. package/package.json +51 -0
@@ -0,0 +1,385 @@
1
+ import { FullRenderingModule } from 'wok-ui';
2
+ import { getWokUiExtI18n } from '../i18n';
3
+ import { hideLoading, showLoading } from '../loading';
4
+ import { showWarning } from '../toast';
5
+ import { DraggingImg } from './dragging-img';
6
+ import { Node } from './node';
7
+ import './style.css';
8
+ /**
9
+ * 树
10
+ */
11
+ export class Tree extends FullRenderingModule {
12
+ constructor(opts) {
13
+ super(document.createElement('ul'));
14
+ this.opts = opts;
15
+ /**
16
+ * 已选id列表
17
+ */
18
+ this.selectedIds = [];
19
+ /**
20
+ * 事件处理器
21
+ */
22
+ this.eventHandler = {};
23
+ this.el.classList.add('wok-ui-ext-tree');
24
+ this.data = [...opts.data];
25
+ this.selectedIds = opts.selectedIds ? [...opts.selectedIds] : [];
26
+ this.render();
27
+ }
28
+ buildContent() {
29
+ // 创建根节点
30
+ this.data.forEach((item, idx) => this.addChild(new Node({
31
+ level: 1,
32
+ buildTitleModule: this.opts.buildTitleModule,
33
+ maxLevel: this.opts.maxLevel && this.opts.maxLevel > 0 ? this.opts.maxLevel : 10,
34
+ data: item,
35
+ hasNextSibling: idx < this.data.length - 1,
36
+ isLast: idx === this.data.length - 1,
37
+ enableMove: this.opts.enableMove,
38
+ selectedIds: this.selectedIds,
39
+ onDragStart: (node, coord) => this.handleDragStart(node, coord),
40
+ selectHook: id => this.handleSelect(id),
41
+ unSelectHook: id => {
42
+ const idx = this.selectedIds.indexOf(id);
43
+ if (idx !== -1) {
44
+ this.selectedIds.splice(idx, 1);
45
+ this.triggerSelectChange();
46
+ }
47
+ return true;
48
+ },
49
+ // 折叠与否也会触发数据变化,折叠标识是数据的一部分
50
+ onFold: () => this.triggerChange(),
51
+ onUnfold: () => this.triggerChange(),
52
+ buildActions: this.opts.buildActions
53
+ })));
54
+ }
55
+ triggerChange() {
56
+ if (this.opts.onChange) {
57
+ this.opts.onChange(this.data);
58
+ }
59
+ }
60
+ triggerSelectChange() {
61
+ if (this.opts.onSelectChange) {
62
+ const res = this.find(m => m instanceof Node)
63
+ .filter(n => this.selectedIds.includes(n.data.id))
64
+ .map(n => Object.assign({}, n.data, { level: n.level }));
65
+ this.opts.onSelectChange(res);
66
+ }
67
+ }
68
+ handleSelect(id) {
69
+ const maxSelected = typeof this.opts.maxSelected === 'number' && this.opts.maxSelected > 0
70
+ ? this.opts.maxSelected
71
+ : 1;
72
+ if (maxSelected === 1) {
73
+ this.find(m => m instanceof Node).forEach(node => {
74
+ if (node.data.id !== id) {
75
+ node.unSelect();
76
+ }
77
+ });
78
+ // 不要改变 selectedIds 的引用,节点和这里共用一个对象
79
+ this.selectedIds.splice(0, this.selectedIds.length);
80
+ this.selectedIds.push(id);
81
+ this.triggerSelectChange();
82
+ return true;
83
+ }
84
+ if (this.selectedIds.length >= maxSelected) {
85
+ showWarning(getWokUiExtI18n().buildMsg('tree-max-selected', `${maxSelected}`));
86
+ return false;
87
+ }
88
+ if (!this.selectedIds.includes(id)) {
89
+ this.selectedIds.push(id);
90
+ this.triggerSelectChange();
91
+ }
92
+ return true;
93
+ }
94
+ /**
95
+ * 对节点取消选择
96
+ * @param id 节点数据的 id
97
+ * @returns
98
+ */
99
+ unselectNode(id) {
100
+ if (!this.selectedIds.length) {
101
+ return;
102
+ }
103
+ const idx = this.selectedIds.indexOf(id);
104
+ if (idx === -1) {
105
+ return;
106
+ }
107
+ this.selectedIds.splice(idx, 1);
108
+ this.find(m => m instanceof Node && m.data.id === id).forEach(node => node.unSelect());
109
+ this.triggerSelectChange();
110
+ }
111
+ /**
112
+ * 处理拖动开始事件,生成拖动图标
113
+ * @param sourceNode 被拖动的原始节点
114
+ * @param coord 事件坐标
115
+ */
116
+ handleDragStart(sourceNode, coord) {
117
+ // 更改状态,添加拖动图标
118
+ this.el.classList.add('wok-ui-ext-dragging');
119
+ if (!this.draggingImg) {
120
+ this.draggingImg = new DraggingImg(sourceNode.data.title);
121
+ this.draggingImg.updateCoord(coord.x, coord.y);
122
+ this.addChild(this.draggingImg);
123
+ }
124
+ // 构建事件处理
125
+ this.eventHandler.dragEnd = ev => {
126
+ ev.preventDefault();
127
+ if (ev.type === 'mouseout') {
128
+ if (ev.target !== document.body) {
129
+ return;
130
+ }
131
+ }
132
+ this.el.classList.remove('wok-ui-ext-dragging');
133
+ if (this.draggingImg) {
134
+ this.draggingImg.destroy();
135
+ this.draggingImg = undefined;
136
+ }
137
+ Promise.resolve()
138
+ .then(async () => {
139
+ // 目标
140
+ if (!this.dragTarget) {
141
+ return;
142
+ }
143
+ showLoading();
144
+ try {
145
+ if (this.opts.moveHook) {
146
+ await this.opts.moveHook(sourceNode.data, this.dragTarget.node.data, this.dragTarget.placement);
147
+ }
148
+ }
149
+ finally {
150
+ hideLoading();
151
+ }
152
+ // 调整成功,更改元素位置
153
+ this.moveNode(sourceNode.data.id, this.dragTarget.node.data.id, this.dragTarget.placement);
154
+ })
155
+ .catch(showWarning)
156
+ .finally(() => {
157
+ this.dragTarget = undefined;
158
+ this.unbindEvents();
159
+ });
160
+ };
161
+ document.body.addEventListener('mouseup', this.eventHandler.dragEnd);
162
+ document.body.addEventListener('mouseout', this.eventHandler.dragEnd);
163
+ document.body.addEventListener('touchend', this.eventHandler.dragEnd);
164
+ document.body.addEventListener('touchcancel', this.eventHandler.dragEnd);
165
+ // 获取当前可见的节点,在拖动过程中节点的可见性不会改变
166
+ // 只让可见的节点在拖动过程中发生变化,进行响应,节省开销
167
+ // 如果轮询所有节点,节点一多就会卡顿
168
+ const visiblesNodes = this.getVisibleNodes();
169
+ // 为了兼容,改由容器来处理悬浮的事件,判定指针或触控点是否被条目包含
170
+ // 移动端的 touchemove 无法通过 touch-action 来跳过层级在前的元素
171
+ // 总是被层级在前的元素触发,所以无法让 item 自己完成处理再反馈给上层
172
+ this.eventHandler.dragOver = ev => {
173
+ // 非拖动中,不处理
174
+ if (!this.el.classList.contains('wok-ui-ext-dragging')) {
175
+ return;
176
+ }
177
+ const clientX = ev instanceof TouchEvent ? ev.touches[0].clientX : ev.clientX;
178
+ const clientY = ev instanceof TouchEvent ? ev.touches[0].clientY : ev.clientY;
179
+ if (this.draggingImg) {
180
+ this.draggingImg.updateCoord(clientX, clientY);
181
+ }
182
+ this.dragTarget = undefined;
183
+ visiblesNodes.forEach(node => {
184
+ const res = node.handleDragOverAndReact(sourceNode.data, clientX, clientY);
185
+ if (res) {
186
+ this.dragTarget = {
187
+ node: node,
188
+ placement: res
189
+ };
190
+ }
191
+ });
192
+ };
193
+ document.body.addEventListener('mousemove', this.eventHandler.dragOver);
194
+ document.body.addEventListener('touchmove', this.eventHandler.dragOver);
195
+ }
196
+ /**
197
+ * 获取所有当前可见的节点
198
+ */
199
+ getVisibleNodes() {
200
+ const res = [];
201
+ const rootNodes = this.getChildren()
202
+ .filter(m => m instanceof Node)
203
+ .map(m => m);
204
+ function getDescendantVisibleNodes(node) {
205
+ const res = [];
206
+ if (node.data.unfolded) {
207
+ for (const subNode of node.getSubNodes()) {
208
+ res.push(subNode);
209
+ res.push(...getDescendantVisibleNodes(subNode));
210
+ }
211
+ }
212
+ return res;
213
+ }
214
+ for (const node of rootNodes) {
215
+ res.push(node);
216
+ res.push(...getDescendantVisibleNodes(node));
217
+ }
218
+ return res;
219
+ }
220
+ /**
221
+ * 移动节点
222
+ * @param sourceNodeId
223
+ * @param targetNodeId
224
+ * @param placement
225
+ */
226
+ moveNode(sourceNodeId, targetNodeId, placement) {
227
+ const sourceNode = this.getNodeModule(sourceNodeId);
228
+ const targetNode = this.getNodeModule(targetNodeId);
229
+ if (!sourceNode || !targetNode) {
230
+ return;
231
+ }
232
+ this.internalDeleteNode(sourceNodeId);
233
+ if (placement === 'in') {
234
+ targetNode.addSubNode(sourceNode.data);
235
+ this.triggerChange();
236
+ return;
237
+ }
238
+ const targetParent = targetNode.getParentNode();
239
+ if (targetParent) {
240
+ if (!targetParent.data.children) {
241
+ return;
242
+ }
243
+ const { children } = targetParent.data;
244
+ const idx = children.findIndex(c => c.id === targetNodeId);
245
+ switch (placement) {
246
+ case 'before':
247
+ targetParent.insertSubNode(sourceNode.data, idx);
248
+ break;
249
+ case 'after':
250
+ targetParent.insertSubNode(sourceNode.data, idx + 1);
251
+ break;
252
+ }
253
+ }
254
+ else {
255
+ const idx = this.data.findIndex(da => da.id === targetNodeId);
256
+ switch (placement) {
257
+ case 'before':
258
+ this.data.splice(idx, 0, sourceNode.data);
259
+ this.render();
260
+ break;
261
+ case 'after':
262
+ this.data.splice(idx + 1, 0, sourceNode.data);
263
+ this.render();
264
+ break;
265
+ }
266
+ }
267
+ this.triggerChange();
268
+ }
269
+ /**
270
+ * 删除一个节点
271
+ * @param id
272
+ */
273
+ deleteNode(id) {
274
+ const res = this.internalDeleteNode(id);
275
+ if (!res) {
276
+ return;
277
+ }
278
+ // 如果已选有包含,则触发回调
279
+ const sIdx = this.selectedIds.indexOf(id);
280
+ if (sIdx !== -1) {
281
+ this.selectedIds.splice(sIdx, 1);
282
+ this.triggerSelectChange();
283
+ }
284
+ }
285
+ /**
286
+ * 内部的删除方法,仅删除节点数据,不触发任何行为
287
+ */
288
+ internalDeleteNode(id) {
289
+ // 找到节点,然后销毁,同步树中的数据
290
+ const node = this.getNodeModule(id);
291
+ if (!node) {
292
+ return false;
293
+ }
294
+ const parent = node.getParentNode();
295
+ if (parent) {
296
+ parent.removeSubNode(node.data.id);
297
+ return true;
298
+ }
299
+ else {
300
+ const idx = this.data.findIndex(da => da.id === id);
301
+ if (idx !== -1) {
302
+ this.data.splice(idx, 1);
303
+ this.triggerChange();
304
+ this.render();
305
+ return true;
306
+ }
307
+ return false;
308
+ }
309
+ }
310
+ /**
311
+ * 更新节点
312
+ * @param data
313
+ */
314
+ updateNode(data) {
315
+ const nodeModule = this.getNodeModule(data.id);
316
+ if (nodeModule) {
317
+ nodeModule.updateTitle(data.title);
318
+ this.triggerChange();
319
+ }
320
+ }
321
+ /**
322
+ * 添加一个节点
323
+ */
324
+ addNode(data, parentId) {
325
+ if (!parentId) {
326
+ this.data.push(data);
327
+ this.render();
328
+ this.triggerChange();
329
+ return;
330
+ }
331
+ const parent = this.getNodeModule(parentId);
332
+ if (parent) {
333
+ parent.addSubNode(data);
334
+ this.triggerChange();
335
+ }
336
+ }
337
+ getNodeModule(id) {
338
+ return this.findFirst(m => m instanceof Node && m.data.id === id);
339
+ }
340
+ /**
341
+ * 获取节点信息
342
+ * @param id 节点id
343
+ */
344
+ getNode(id) {
345
+ const node = this.getNodeModule(id);
346
+ if (node) {
347
+ return { ...node.data };
348
+ }
349
+ return undefined;
350
+ }
351
+ /**
352
+ * 获取一个节点的父节点信息,如果找不到节点,或者节点是根节点不存在父节点,则返回 undefined
353
+ * @param id
354
+ */
355
+ getParentNode(id) {
356
+ const node = this.getNodeModule(id);
357
+ if (node) {
358
+ const p = node.getParentNode();
359
+ if (p) {
360
+ return { ...p.data };
361
+ }
362
+ }
363
+ return undefined;
364
+ }
365
+ /**
366
+ * 解绑事件
367
+ */
368
+ unbindEvents() {
369
+ if (this.eventHandler.dragEnd) {
370
+ document.body.removeEventListener('mouseup', this.eventHandler.dragEnd);
371
+ document.body.removeEventListener('mouseover', this.eventHandler.dragEnd);
372
+ document.body.removeEventListener('touchend', this.eventHandler.dragEnd);
373
+ document.body.removeEventListener('touchcancel', this.eventHandler.dragEnd);
374
+ this.eventHandler.dragEnd = undefined;
375
+ }
376
+ if (this.eventHandler.dragOver) {
377
+ this.el.removeEventListener('mousemove', this.eventHandler.dragOver);
378
+ this.el.removeEventListener('touchmove', this.eventHandler.dragOver);
379
+ }
380
+ }
381
+ destroy() {
382
+ this.unbindEvents();
383
+ super.destroy();
384
+ }
385
+ }
@@ -0,0 +1,63 @@
1
+ import { ConvertibleModule, FullRenderingModule } from 'wok-ui';
2
+ import { TreeNodeData } from '.';
3
+ import { ShowContextMenuOpts } from '../context-menu';
4
+ /**
5
+ * 节点信息模块
6
+ */
7
+ export declare class NodeInfo<T extends TreeNodeData> extends FullRenderingModule {
8
+ private opts;
9
+ private mouseDownTimerId;
10
+ constructor(opts: {
11
+ /**
12
+ * 层级,从 1 开始
13
+ */
14
+ level: number;
15
+ /**
16
+ * 是否已经达到最大层级,如果是则不支持拖动放入,只能拖动到前面或后面
17
+ */
18
+ isMaxLevel: boolean;
19
+ /**
20
+ * 数据
21
+ */
22
+ data: T;
23
+ /**
24
+ * 启动拖动
25
+ */
26
+ enableDrag?: boolean;
27
+ /**
28
+ * 开始拖动的监听
29
+ * @param listener
30
+ */
31
+ onDragStart: (coord: {
32
+ x: number;
33
+ y: number;
34
+ }) => void;
35
+ /**
36
+ * 点击回调
37
+ * @returns
38
+ */
39
+ onClick: () => void;
40
+ /**
41
+ * 切换折叠状态回调
42
+ */
43
+ onToggleFold: () => void;
44
+ /**
45
+ * 构造节点的操作项,如果未定义,或返回的空数组,都不会显示出菜单项
46
+ */
47
+ buildActions?: () => ShowContextMenuOpts['menu'];
48
+ /**
49
+ * 构造节点的标题模块,默认显示 title 属性文本
50
+ * @returns
51
+ */
52
+ buildTitleModule?: (data: T) => ConvertibleModule;
53
+ });
54
+ protected buildContent(): void;
55
+ /**
56
+ * 判定是否包含一个指定的坐标,并做出反应
57
+ * @param pageX
58
+ * @param pageY
59
+ * @returns 不包含,或者包含的情况下,是在上部分还是下部分
60
+ */
61
+ handleDragOverAndReact(pageX: number, pageY: number): false | 'before' | 'after' | 'in';
62
+ removeMovingStyle(): void;
63
+ }
@@ -0,0 +1,128 @@
1
+ import { FullRenderingModule } from 'wok-ui';
2
+ import { IconFolderOpen, IconFolder, IconLock, IconEllipsisH } from '../icons';
3
+ import { showContextMenu } from '../context-menu';
4
+ /**
5
+ * 节点信息模块
6
+ */
7
+ export class NodeInfo extends FullRenderingModule {
8
+ constructor(opts) {
9
+ super('wok-ui-ext-node-info');
10
+ this.opts = opts;
11
+ // 拖动事件处理
12
+ this.el.onmousedown = ev => {
13
+ if (ev.button !== 0)
14
+ return;
15
+ ev.preventDefault();
16
+ ev.stopPropagation();
17
+ // 为了避免冲突(与点击同时触发),在按下一定时间后才触发拖动
18
+ this.mouseDownTimerId = setTimeout(() => {
19
+ this.mouseDownTimerId = undefined;
20
+ if (opts.enableDrag) {
21
+ opts.onDragStart({ x: ev.clientX, y: ev.clientY });
22
+ }
23
+ }, 300);
24
+ this.el.onmouseleave = ev => {
25
+ if (ev.button !== 0)
26
+ return;
27
+ clearTimeout(this.mouseDownTimerId);
28
+ };
29
+ this.el.onmouseup = ev => {
30
+ if (ev.button !== 0)
31
+ return;
32
+ if (this.mouseDownTimerId) {
33
+ clearTimeout(this.mouseDownTimerId);
34
+ this.mouseDownTimerId = undefined;
35
+ opts.onClick();
36
+ }
37
+ };
38
+ };
39
+ this.render();
40
+ }
41
+ buildContent() {
42
+ // 折叠图标
43
+ if (this.opts.data.children && this.opts.data.children.length) {
44
+ // 折叠图标
45
+ this.addChild({
46
+ classNames: 'wok-ui-ext-icon-fold',
47
+ children: this.opts.data.unfolded ? new IconFolderOpen() : new IconFolder(),
48
+ events: {
49
+ mousedown: e => e.stopPropagation(),
50
+ mouseleave: e => e.stopPropagation(),
51
+ mouseup: e => e.stopPropagation()
52
+ },
53
+ onClick: e => {
54
+ e.stopPropagation();
55
+ e.preventDefault();
56
+ this.opts.onToggleFold();
57
+ }
58
+ });
59
+ }
60
+ // 节点名称
61
+ this.addChild({
62
+ classNames: 'wok-ui-ext-node-name',
63
+ children: this.opts.buildTitleModule?.(this.opts.data) || this.opts.data.title
64
+ });
65
+ // 如果全局开启了移动,但是又节点又锁住了,则显示一个锁的图标
66
+ if (this.opts.enableDrag && this.opts.data.unmoveable) {
67
+ this.addChild(new IconLock());
68
+ }
69
+ // 操作项
70
+ const menu = this.opts.buildActions?.();
71
+ if (menu && menu.length) {
72
+ this.addChild({
73
+ classNames: 'wok-ui-ext-icon-manage',
74
+ children: new IconEllipsisH(),
75
+ events: {
76
+ mousedown: e => e.stopPropagation(),
77
+ mouseleave: e => e.stopPropagation(),
78
+ mouseup: e => e.stopPropagation()
79
+ },
80
+ onClick(e) {
81
+ e.stopPropagation();
82
+ // 弹出操作项
83
+ showContextMenu({
84
+ menu,
85
+ evt: e
86
+ });
87
+ }
88
+ });
89
+ }
90
+ }
91
+ /**
92
+ * 判定是否包含一个指定的坐标,并做出反应
93
+ * @param pageX
94
+ * @param pageY
95
+ * @returns 不包含,或者包含的情况下,是在上部分还是下部分
96
+ */
97
+ handleDragOverAndReact(pageX, pageY) {
98
+ this.removeMovingStyle();
99
+ const rect = this.el.getBoundingClientRect();
100
+ // 向右偏出 100px 也可以支持,这是为了移动端拖动时,手指拖动到旁边也可以成功
101
+ if (pageX < rect.x || pageX > rect.x + rect.width + 100) {
102
+ return false;
103
+ }
104
+ const offsetY = pageY - rect.y;
105
+ if (offsetY < 0 || offsetY > rect.height) {
106
+ return false;
107
+ }
108
+ // 上中下
109
+ if (offsetY < rect.height / 3) {
110
+ this.el.classList.add('wok-ui-ext-moving-before');
111
+ return 'before';
112
+ }
113
+ else if (offsetY < (rect.height / 3) * 2) {
114
+ if (this.opts.isMaxLevel) {
115
+ return false;
116
+ }
117
+ this.el.classList.add('wok-ui-ext-moving-in');
118
+ return 'in';
119
+ }
120
+ else {
121
+ this.el.classList.add('wok-ui-ext-moving-after');
122
+ return 'after';
123
+ }
124
+ }
125
+ removeMovingStyle() {
126
+ this.el.classList.remove('wok-ui-ext-moving-before', 'wok-ui-ext-moving-after', 'wok-ui-ext-moving-in');
127
+ }
128
+ }
@@ -0,0 +1,132 @@
1
+ import { ConvertibleModule, FullRenderingModule } from 'wok-ui';
2
+ import { ShowContextMenuOpts } from '../context-menu';
3
+ import { TreeNodeData } from '.';
4
+ /**
5
+ * 节点,包含自身信息以及子节点列表
6
+ */
7
+ export declare class Node<T extends TreeNodeData> extends FullRenderingModule {
8
+ private opts;
9
+ private subNodesEl?;
10
+ /**
11
+ * 节点数据,记录基本信息,以及状态信息,随着节点样式的变化一起更新
12
+ */
13
+ readonly data: T;
14
+ readonly level: number;
15
+ private subNodes;
16
+ private nodeInfo?;
17
+ constructor(opts: {
18
+ /**
19
+ * 父节点,记录父节点信息目的是为了能更快的查找
20
+ */
21
+ parent?: Node<T>;
22
+ /**
23
+ * 层级,从 1 开始
24
+ */
25
+ level: number;
26
+ /**
27
+ * 最大层级
28
+ */
29
+ maxLevel: number;
30
+ /**
31
+ * 是否有下一个兄弟元素
32
+ */
33
+ hasNextSibling: boolean;
34
+ /**
35
+ * 是否最后一个
36
+ */
37
+ isLast: boolean;
38
+ /**
39
+ * 已经 id 列表
40
+ */
41
+ selectedIds: string[];
42
+ /**
43
+ * 数据
44
+ */
45
+ data: T;
46
+ /**
47
+ * 启动移动功能,启动后支持拖动节点来改变节点的位置
48
+ */
49
+ enableMove?: boolean;
50
+ /**
51
+ * 开始拖动的监听
52
+ * @param listener
53
+ */
54
+ onDragStart: (node: Node<T>, coord: {
55
+ x: number;
56
+ y: number;
57
+ }) => void;
58
+ /**
59
+ * 选中钩子函数
60
+ * @returns
61
+ */
62
+ selectHook: (id: string) => boolean;
63
+ /**
64
+ * 取消选中钩子
65
+ * @returns
66
+ */
67
+ unSelectHook: (id: string) => boolean;
68
+ /**
69
+ * 折叠回调
70
+ * @returns
71
+ */
72
+ onFold: (node: Node<T>) => void;
73
+ /**
74
+ * 展开回调
75
+ * @returns
76
+ */
77
+ onUnfold: (node: Node<T>) => void;
78
+ /**
79
+ * 构造节点的操作项,如果未定义,或返回的空数组,都不会显示出菜单项
80
+ */
81
+ buildActions?: (data: T, level: number) => ShowContextMenuOpts['menu'];
82
+ buildTitleModule?: (data: T) => ConvertibleModule;
83
+ });
84
+ private buildInfo;
85
+ private updateInfo;
86
+ protected buildContent(): void;
87
+ /**
88
+ * 主动取消选中
89
+ */
90
+ unSelect(): void;
91
+ private fold;
92
+ /**
93
+ * 展开,为了让子节点元素有动画,必须得指定宽度(auto 高度不会产生动画),宽度需要根据子节点的情况进行计算
94
+ */
95
+ private unfold;
96
+ /**
97
+ * 更新标题
98
+ * @param title
99
+ */
100
+ updateTitle(title: TreeNodeData['title']): void;
101
+ /**
102
+ * 删除子节点
103
+ * @param subNodeId 子节点ID
104
+ */
105
+ removeSubNode(subNodeId: string): void;
106
+ /**
107
+ * 添加子节点
108
+ * @param subNodeData 子节点数据
109
+ */
110
+ addSubNode(subNodeData: T): void;
111
+ /**
112
+ * 插入子节点,到指定位置
113
+ * @param subNodeData 子节点数据
114
+ */
115
+ insertSubNode(subNodeData: T, targetIdx: number): void;
116
+ /**
117
+ * 获取子节点
118
+ */
119
+ getSubNodes(): Node<T>[];
120
+ /**
121
+ * 获取父节点模块
122
+ */
123
+ getParentNode(): Node<T> | undefined;
124
+ /**
125
+ * 处理拖动悬浮并反应调整样式
126
+ * @param sourceNode 源节点,即要移动的节点
127
+ * @param clientX 横坐标
128
+ * @param clientY 纵坐标
129
+ * @returns
130
+ */
131
+ handleDragOverAndReact(sourceNode: TreeNodeData, clientX: number, clientY: number): false | 'before' | 'after' | 'in';
132
+ }