amis 1.4.1 → 1.4.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +1 -1
  2. package/lib/Schema.d.ts +17 -0
  3. package/lib/Schema.js.map +1 -1
  4. package/lib/components/Alert.js +3 -1
  5. package/lib/components/Alert.js.map +2 -2
  6. package/lib/components/Badge.d.ts +2 -2
  7. package/lib/components/Badge.js +12 -6
  8. package/lib/components/Badge.js.map +2 -2
  9. package/lib/components/Collapse.js +1 -1
  10. package/lib/components/Collapse.js.map +2 -2
  11. package/lib/components/DatePicker.js +1 -1
  12. package/lib/components/DatePicker.js.map +2 -2
  13. package/lib/components/DateRangePicker.js +1 -1
  14. package/lib/components/DateRangePicker.js.map +2 -2
  15. package/lib/components/InputBox.js +1 -1
  16. package/lib/components/InputBox.js.map +2 -2
  17. package/lib/components/Link.d.ts +91 -0
  18. package/lib/components/Link.js +44 -0
  19. package/lib/components/Link.js.map +13 -0
  20. package/lib/components/MonthRangePicker.js +1 -1
  21. package/lib/components/MonthRangePicker.js.map +2 -2
  22. package/lib/components/RichText.js +17 -53
  23. package/lib/components/RichText.js.map +2 -2
  24. package/lib/components/Select.js +3 -0
  25. package/lib/components/Select.js.map +2 -2
  26. package/lib/components/SparkLine.d.ts +85 -84
  27. package/lib/components/SparkLine.js +2 -2
  28. package/lib/components/SparkLine.js.map +2 -2
  29. package/lib/components/Toast.js +2 -2
  30. package/lib/components/Toast.js.map +2 -2
  31. package/lib/components/Tree.js +5 -3
  32. package/lib/components/Tree.js.map +2 -2
  33. package/lib/components/icons.js +12 -0
  34. package/lib/components/icons.js.map +2 -2
  35. package/lib/icons/clock.js +10 -0
  36. package/lib/icons/status-close.js +11 -0
  37. package/lib/icons/status-fail.js +11 -0
  38. package/lib/icons/status-info.js +10 -0
  39. package/lib/icons/status-success.js +11 -0
  40. package/lib/icons/status-warning.js +10 -0
  41. package/lib/index.js +1 -1
  42. package/lib/locale/de-DE.js +2 -0
  43. package/lib/locale/de-DE.js.map +2 -2
  44. package/lib/locale/en-US.js +2 -0
  45. package/lib/locale/en-US.js.map +2 -2
  46. package/lib/locale/zh-CN.js +3 -1
  47. package/lib/locale/zh-CN.js.map +2 -2
  48. package/lib/renderers/Action.d.ts +7 -0
  49. package/lib/renderers/Action.js.map +2 -2
  50. package/lib/renderers/CRUD.js +21 -6
  51. package/lib/renderers/CRUD.js.map +2 -2
  52. package/lib/renderers/Collapse.js +2 -2
  53. package/lib/renderers/Collapse.js.map +2 -2
  54. package/lib/renderers/Dialog.js +0 -3
  55. package/lib/renderers/Dialog.js.map +2 -2
  56. package/lib/renderers/Drawer.js +0 -3
  57. package/lib/renderers/Drawer.js.map +2 -2
  58. package/lib/renderers/DropDownButton.d.ts +5 -1
  59. package/lib/renderers/DropDownButton.js +8 -6
  60. package/lib/renderers/DropDownButton.js.map +2 -2
  61. package/lib/renderers/Form/Checkbox.d.ts +5 -0
  62. package/lib/renderers/Form/Checkbox.js +4 -0
  63. package/lib/renderers/Form/Checkbox.js.map +2 -2
  64. package/lib/renderers/Form/Combo.js +2 -2
  65. package/lib/renderers/Form/Combo.js.map +2 -2
  66. package/lib/renderers/Form/InputFile.js +2 -2
  67. package/lib/renderers/Form/InputFile.js.map +2 -2
  68. package/lib/renderers/Form/InputImage.js +5 -3
  69. package/lib/renderers/Form/InputImage.js.map +2 -2
  70. package/lib/renderers/Form/Options.js +6 -3
  71. package/lib/renderers/Form/Options.js.map +2 -2
  72. package/lib/renderers/Form/Picker.js +2 -2
  73. package/lib/renderers/Form/Picker.js.map +2 -2
  74. package/lib/renderers/Form/wrapControl.js +2 -2
  75. package/lib/renderers/Form/wrapControl.js.map +2 -2
  76. package/lib/renderers/IFrame.js +2 -2
  77. package/lib/renderers/IFrame.js.map +2 -2
  78. package/lib/renderers/Image.d.ts +1 -0
  79. package/lib/renderers/Image.js +15 -1
  80. package/lib/renderers/Image.js.map +2 -2
  81. package/lib/renderers/Link.d.ts +16 -3
  82. package/lib/renderers/Link.js +16 -13
  83. package/lib/renderers/Link.js.map +2 -2
  84. package/lib/renderers/Log.d.ts +2 -2
  85. package/lib/renderers/Log.js +7 -1
  86. package/lib/renderers/Log.js.map +2 -2
  87. package/lib/renderers/Nav.d.ts +62 -36
  88. package/lib/renderers/Nav.js +248 -90
  89. package/lib/renderers/Nav.js.map +2 -2
  90. package/lib/renderers/SparkLine.d.ts +4 -0
  91. package/lib/renderers/SparkLine.js.map +2 -2
  92. package/lib/renderers/Table/ColumnToggler.d.ts +113 -0
  93. package/lib/renderers/Table/ColumnToggler.js +216 -0
  94. package/lib/renderers/Table/ColumnToggler.js.map +13 -0
  95. package/lib/renderers/Table/ItemActionsWrapper.d.ts +11 -0
  96. package/lib/renderers/Table/ItemActionsWrapper.js +31 -0
  97. package/lib/renderers/Table/ItemActionsWrapper.js.map +13 -0
  98. package/lib/renderers/Table/TableBody.d.ts +4 -0
  99. package/lib/renderers/Table/TableCell.js +3 -1
  100. package/lib/renderers/Table/TableCell.js.map +2 -2
  101. package/lib/renderers/Table/index.d.ts +14 -1
  102. package/lib/renderers/Table/index.js +116 -36
  103. package/lib/renderers/Table/index.js.map +2 -2
  104. package/lib/store/table.d.ts +257 -1
  105. package/lib/store/table.js +41 -6
  106. package/lib/store/table.js.map +2 -2
  107. package/lib/themes/ang-ie11.css +393 -90
  108. package/lib/themes/ang.css +393 -90
  109. package/lib/themes/ang.css.map +1 -1
  110. package/lib/themes/antd-ie11.css +393 -90
  111. package/lib/themes/antd.css +393 -90
  112. package/lib/themes/antd.css.map +1 -1
  113. package/lib/themes/cxd-ie11.css +904 -263
  114. package/lib/themes/cxd.css +904 -263
  115. package/lib/themes/cxd.css.map +1 -1
  116. package/lib/themes/dark-ie11.css +393 -90
  117. package/lib/themes/dark.css +393 -90
  118. package/lib/themes/dark.css.map +1 -1
  119. package/lib/themes/default.css +904 -263
  120. package/lib/themes/default.css.map +1 -1
  121. package/lib/utils/api.js +4 -4
  122. package/lib/utils/api.js.map +2 -2
  123. package/lib/utils/handleAction.d.ts +7 -0
  124. package/lib/utils/handleAction.js +30 -0
  125. package/lib/utils/handleAction.js.map +13 -0
  126. package/lib/utils/helper.d.ts +1 -1
  127. package/lib/utils/helper.js +3 -3
  128. package/lib/utils/helper.js.map +2 -2
  129. package/lib/utils/tpl-builtin.d.ts +1 -1
  130. package/lib/utils/tpl-builtin.js +25 -15
  131. package/lib/utils/tpl-builtin.js.map +2 -2
  132. package/package.json +1 -1
  133. package/schema.json +322 -261
  134. package/scss/_properties.scss +39 -4
  135. package/scss/_utilities.scss +4 -0
  136. package/scss/components/_button.scss +4 -5
  137. package/scss/components/_collapse.scss +26 -8
  138. package/scss/components/_column-toggler.scss +234 -0
  139. package/scss/components/_dropdown.scss +2 -1
  140. package/scss/components/_images.scss +2 -1
  141. package/scss/components/_link.scss +6 -0
  142. package/scss/components/_nav.scss +231 -223
  143. package/scss/components/_page.scss +5 -4
  144. package/scss/components/_progress.scss +2 -0
  145. package/scss/components/_steps.scss +1 -1
  146. package/scss/components/_table.scss +25 -1
  147. package/scss/components/form/_color.scss +1 -0
  148. package/scss/components/form/_date-range.scss +2 -0
  149. package/scss/components/form/_date.scss +2 -0
  150. package/scss/components/form/_fieldset.scss +1 -2
  151. package/scss/components/form/_file.scss +5 -4
  152. package/scss/components/form/_image.scss +7 -2
  153. package/scss/components/form/_list.scss +1 -0
  154. package/scss/components/form/_location.scss +1 -1
  155. package/scss/components/form/_text.scss +13 -0
  156. package/scss/components/form/_textarea.scss +10 -0
  157. package/scss/components/form/_transfer.scss +2 -0
  158. package/scss/themes/_common.scss +2 -0
  159. package/scss/themes/_cxd-colors.scss +56 -0
  160. package/scss/themes/_cxd-variables.scss +215 -90
  161. package/scss/themes/cxd.scss +366 -0
  162. package/sdk/ang-ie11.css +569 -235
  163. package/sdk/ang.css +512 -151
  164. package/sdk/antd-ie11.css +558 -224
  165. package/sdk/antd.css +512 -151
  166. package/sdk/charts.js +13 -13
  167. package/sdk/color-picker.js +67 -67
  168. package/sdk/cropperjs.js +2 -2
  169. package/sdk/cxd-ie11.css +1506 -870
  170. package/sdk/cxd.css +1064 -324
  171. package/sdk/dark-ie11.css +569 -235
  172. package/sdk/dark.css +512 -151
  173. package/sdk/exceljs.js +1 -1
  174. package/sdk/ie11-patch.css +1 -0
  175. package/sdk/locale/de-DE.js +2 -0
  176. package/sdk/markdown.js +69 -69
  177. package/sdk/papaparse.js +1 -1
  178. package/sdk/renderers/Form/CityDB.js +1 -1
  179. package/sdk/rest.js +22 -22
  180. package/sdk/rich-text.js +62 -62
  181. package/sdk/sdk-ie11.css +1506 -870
  182. package/sdk/sdk.css +1064 -324
  183. package/sdk/sdk.js +1138 -1118
  184. package/sdk/thirds/hls.js/hls.js +1 -1
  185. package/sdk/thirds/mpegts.js/mpegts.js +1 -1
  186. package/sdk/tinymce.js +57 -57
  187. package/src/Schema.ts +18 -0
  188. package/src/components/Alert.tsx +3 -1
  189. package/src/components/Badge.tsx +36 -24
  190. package/src/components/Collapse.tsx +14 -9
  191. package/src/components/DatePicker.tsx +1 -1
  192. package/src/components/DateRangePicker.tsx +23 -11
  193. package/src/components/InputBox.tsx +1 -1
  194. package/src/components/Link.tsx +94 -0
  195. package/src/components/MonthRangePicker.tsx +10 -2
  196. package/src/components/RichText.tsx +17 -57
  197. package/src/components/Select.tsx +3 -0
  198. package/src/components/SparkLine.tsx +4 -1
  199. package/src/components/Toast.tsx +5 -5
  200. package/src/components/Tree.tsx +6 -8
  201. package/src/components/icons.tsx +13 -0
  202. package/src/icons/clock.svg +1 -0
  203. package/src/icons/status-close.svg +10 -0
  204. package/src/icons/status-fail.svg +10 -0
  205. package/src/icons/status-info.svg +8 -0
  206. package/src/icons/status-success.svg +10 -0
  207. package/src/icons/status-warning.svg +8 -0
  208. package/src/locale/de-DE.ts +2 -0
  209. package/src/locale/en-US.ts +2 -0
  210. package/src/locale/zh-CN.ts +3 -1
  211. package/src/renderers/Action.tsx +5 -0
  212. package/src/renderers/CRUD.tsx +31 -26
  213. package/src/renderers/Collapse.tsx +1 -1
  214. package/src/renderers/Dialog.tsx +0 -4
  215. package/src/renderers/Drawer.tsx +0 -4
  216. package/src/renderers/DropDownButton.tsx +19 -14
  217. package/src/renderers/Form/Checkbox.tsx +8 -0
  218. package/src/renderers/Form/Combo.tsx +2 -3
  219. package/src/renderers/Form/InputFile.tsx +2 -1
  220. package/src/renderers/Form/InputImage.tsx +5 -2
  221. package/src/renderers/Form/Options.tsx +16 -5
  222. package/src/renderers/Form/Picker.tsx +3 -2
  223. package/src/renderers/Form/wrapControl.tsx +2 -2
  224. package/src/renderers/IFrame.tsx +2 -1
  225. package/src/renderers/Image.tsx +10 -0
  226. package/src/renderers/Link.tsx +36 -11
  227. package/src/renderers/Log.tsx +16 -3
  228. package/src/renderers/Nav.tsx +255 -100
  229. package/src/renderers/SparkLine.tsx +5 -0
  230. package/src/renderers/Table/ColumnToggler.tsx +544 -0
  231. package/src/renderers/Table/ItemActionsWrapper.tsx +44 -0
  232. package/src/renderers/Table/TableCell.tsx +16 -1
  233. package/src/renderers/Table/index.tsx +179 -47
  234. package/src/store/table.ts +57 -6
  235. package/src/utils/api.ts +13 -4
  236. package/src/utils/handleAction.ts +41 -0
  237. package/src/utils/helper.ts +4 -4
  238. package/src/utils/tpl-builtin.ts +48 -17
  239. package/sdk.zip +0 -0
@@ -4,6 +4,7 @@ import {BaseSchema, SchemaTpl} from '../Schema';
4
4
  import {getPropValue} from '../utils/helper';
5
5
  import {filter} from '../utils/tpl';
6
6
  import {BadgeSchema, withBadge} from '../components/Badge';
7
+ import Link from '../components/Link';
7
8
 
8
9
  /**
9
10
  * Link 链接展示控件。
@@ -29,16 +30,32 @@ export interface LinkSchema extends BaseSchema {
29
30
  * 角标
30
31
  */
31
32
  badge?: BadgeSchema;
33
+
34
+ /**
35
+ * a标签原生target属性
36
+ */
37
+ htmlTarget?: string;
38
+
39
+ /**
40
+ * 图标
41
+ */
42
+ icon?: string;
43
+
44
+ /**
45
+ * 图标位置
46
+ */
47
+ position?: string;
32
48
  }
33
49
 
34
50
  export interface LinkProps
35
51
  extends RendererProps,
36
52
  Omit<LinkSchema, 'type' | 'className'> {}
37
53
 
38
- export class LinkField extends React.Component<LinkProps, object> {
54
+ export class LinkCmpt extends React.Component<LinkProps, object> {
39
55
  static defaultProps = {
40
- className: '',
41
- blank: false
56
+ blank: true,
57
+ disabled: false,
58
+ htmlTarget: '_self'
42
59
  };
43
60
 
44
61
  render() {
@@ -48,25 +65,33 @@ export class LinkField extends React.Component<LinkProps, object> {
48
65
  href,
49
66
  classnames: cx,
50
67
  blank,
68
+ disabled,
51
69
  htmlTarget,
52
70
  data,
53
71
  render,
54
72
  translate: __,
55
- title
73
+ title,
74
+ icon,
75
+ position
56
76
  } = this.props;
57
77
 
58
78
  let value = getPropValue(this.props);
59
79
  const finnalHref = href ? filter(href, data, '| raw') : '';
80
+ const text = body ? render('body', body) : finnalHref || value || __('link');
60
81
 
61
82
  return (
62
- <a
63
- href={finnalHref || value}
64
- target={htmlTarget || (blank ? '_blank' : '_self')}
65
- className={cx('Link', className)}
83
+ <Link
84
+ className={className}
85
+ href={href}
86
+ body={text}
87
+ blank={blank}
88
+ disabled={disabled}
66
89
  title={title}
90
+ htmlTarget={htmlTarget}
91
+ icon={icon}
92
+ position={position}
67
93
  >
68
- {body ? render('body', body) : finnalHref || value || __('link')}
69
- </a>
94
+ </Link>
70
95
  );
71
96
  }
72
97
  }
@@ -76,4 +101,4 @@ export class LinkField extends React.Component<LinkProps, object> {
76
101
  })
77
102
  // @ts-ignore 类型没搞定
78
103
  @withBadge
79
- export class LinkFieldRenderer extends LinkField {}
104
+ export class LinkFieldRenderer extends LinkCmpt {}
@@ -6,7 +6,7 @@ import {Renderer, RendererProps} from '../factory';
6
6
  import {BaseSchema, SchemaTpl} from '../Schema';
7
7
  import Ansi from 'ansi-to-react';
8
8
  import {filter} from '../utils/tpl';
9
- import {buildApi} from '../utils/api';
9
+ import {buildApi, isApiOutdated} from '../utils/api';
10
10
 
11
11
  /**
12
12
  * 日志展示组件
@@ -14,7 +14,7 @@ import {buildApi} from '../utils/api';
14
14
  */
15
15
  export interface LogSchema extends BaseSchema {
16
16
  /**
17
- * 指定为 link 链接展示控件
17
+ * 指定为 log 链接展示控件
18
18
  */
19
19
  type: 'log';
20
20
 
@@ -100,10 +100,20 @@ export class Log extends React.Component<LogProps, LogState> {
100
100
  }
101
101
  }
102
102
 
103
- componentDidUpdate() {
103
+ componentDidUpdate(prevProps: LogProps) {
104
104
  if (this.autoScroll && this.logRef && this.logRef.current) {
105
105
  this.logRef.current.scrollTop = this.logRef.current.scrollHeight;
106
106
  }
107
+ if (
108
+ isApiOutdated(
109
+ prevProps.source,
110
+ this.props.source,
111
+ prevProps.data,
112
+ this.props.data
113
+ )
114
+ ) {
115
+ this.loadLogs();
116
+ }
107
117
  }
108
118
 
109
119
  // 如果向上滚动就停止自动滚动,除非滚到底部
@@ -118,6 +128,9 @@ export class Log extends React.Component<LogProps, LogState> {
118
128
  const {source, data, env, translate: __, encoding} = this.props;
119
129
  // 因为这里返回结果是流式的,和普通 api 请求不一样,如果直接用 fetcher 经过 responseAdaptor 可能会导致出错,所以就直接 fetch 了
120
130
  const api = buildApi(source, data);
131
+ if (!api.url) {
132
+ return;
133
+ }
121
134
  const res = await fetch(api.url);
122
135
  if (res.status === 200) {
123
136
  const body = res.body;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import Sortable from 'sortablejs';
2
+ import {findDOMNode} from 'react-dom';
3
3
  import {Renderer, RendererEnv, RendererProps} from '../factory';
4
4
  import getExprProperties from '../utils/filter-schema';
5
5
  import {filter, evalExpression} from '../utils/tpl';
@@ -11,7 +11,8 @@ import {
11
11
  isUnfolded,
12
12
  mapTree,
13
13
  someTree,
14
- spliceTree
14
+ spliceTree,
15
+ findTreeIndex
15
16
  } from '../utils/helper';
16
17
  import {ScopedContext, IScopedContext} from '../Scoped';
17
18
  import {themeable, ThemeProps} from '../theme';
@@ -24,7 +25,6 @@ import {
24
25
  } from '../components/WithRemoteConfig';
25
26
  import {Payload} from '../types';
26
27
  import Spinner from '../components/Spinner';
27
- import cloneDeep from 'lodash/cloneDeep';
28
28
  import {isEffectiveApi} from '../utils/api';
29
29
  import {Badge, BadgeSchema} from '../components/Badge';
30
30
 
@@ -50,11 +50,6 @@ export type NavItemSchema = {
50
50
  deferApi?: SchemaApi;
51
51
 
52
52
  children?: Array<NavItemSchema>;
53
-
54
- /**
55
- * 角标
56
- */
57
- badge?: BadgeSchema
58
53
  } & Omit<BaseSchema, 'type'>;
59
54
 
60
55
  /**
@@ -110,7 +105,12 @@ export interface NavSchema extends BaseSchema {
110
105
  /**
111
106
  * 角标
112
107
  */
113
- badge?: BadgeSchema;
108
+ itemBadge?: BadgeSchema;
109
+
110
+ /**
111
+ * 仅允许同层级拖拽
112
+ */
113
+ dragOnSameLevel?: boolean;
114
114
  }
115
115
 
116
116
  export interface Link {
@@ -127,28 +127,46 @@ export interface Link {
127
127
  loading?: boolean;
128
128
  loaded?: boolean;
129
129
  [propName: string]: any;
130
- badge?: BadgeSchema
130
+ itemBadge?: BadgeSchema;
131
131
  }
132
132
  export interface Links extends Array<Link> {}
133
133
 
134
134
  export interface NavigationState {
135
- links: Links;
135
+ links?: Links;
136
136
  error?: string;
137
+ dropIndicator?: {
138
+ top: number;
139
+ left: number;
140
+ width: number;
141
+ height?: number;
142
+ opacity?: number;
143
+ };
137
144
  }
138
145
 
139
146
  export interface NavigationProps
140
147
  extends ThemeProps,
141
148
  Omit<NavSchema, 'type' | 'className'> {
142
149
  onSelect?: (item: Link) => void | false;
143
- onToggle?: (item: Link) => void;
150
+ onToggle?: (item: Link, forceFold?: boolean) => void;
151
+ onDragUpdate?: (dropInfo: IDropInfo) => void;
144
152
  togglerClassName?: string;
145
153
  links?: Array<Link>;
146
154
  loading?: boolean;
147
155
  render: RendererProps['render'];
148
156
  env: RendererEnv;
157
+ data: Object;
149
158
  reload?: any;
150
159
  }
151
160
 
161
+ export interface IDropInfo {
162
+ dragLink: Link | null;
163
+ nodeId: string;
164
+ position: string;
165
+ rect: DOMRect;
166
+ height: number;
167
+ left: number;
168
+ }
169
+
152
170
  export class Navigation extends React.Component<
153
171
  NavigationProps,
154
172
  NavigationState
@@ -156,9 +174,20 @@ export class Navigation extends React.Component<
156
174
  static defaultProps = {
157
175
  indentSize: 24
158
176
  };
159
- sortable: Sortable[] = [];
160
- id: string;
161
- dragRef?: HTMLElement;
177
+
178
+ dragNode: {
179
+ node: HTMLElement;
180
+ link: Link | null;
181
+ } | null;
182
+ dropInfo: IDropInfo | null;
183
+ startPoint: {
184
+ y: number;
185
+ x: number;
186
+ } = {
187
+ y: 0,
188
+ x: 0
189
+ };
190
+ state: NavigationState = {};
162
191
 
163
192
  @autobind
164
193
  handleClick(link: Link) {
@@ -166,66 +195,134 @@ export class Navigation extends React.Component<
166
195
  }
167
196
 
168
197
  @autobind
169
- toggleLink(target: Link) {
170
- this.props.onToggle?.(target);
198
+ toggleLink(target: Link, forceFold?: boolean) {
199
+ this.props.onToggle?.(target, forceFold);
171
200
  }
172
201
 
173
202
  @autobind
174
- dragRefFn(ref: any) {
175
- const {draggable} = this.props;
176
- if (ref && draggable) {
177
- this.id = guid();
178
- this.initDragging(ref);
203
+ getDropInfo(e: DragEvent, id: string, depth: number): IDropInfo {
204
+ const {dragOnSameLevel, indentSize} = this.props;
205
+ let rect = (e.target as HTMLElement).getBoundingClientRect();
206
+ const dragLink = this.dragNode?.link as Link;
207
+ const {top, height, width} = rect;
208
+ let {clientY, clientX} = e;
209
+ const left = depth * (parseInt(indentSize as any, 10) ?? 24);
210
+ const deltaX = left + width * .2;
211
+ let position;
212
+ if (clientY >= top + height / 2 ) {
213
+ position = 'bottom';
214
+ } else {
215
+ position = 'top';
179
216
  }
217
+ if (!dragOnSameLevel && position === 'bottom' && clientX >= this.startPoint.x + deltaX) {
218
+ position = 'self';
219
+ }
220
+ return {
221
+ nodeId: id,
222
+ dragLink,
223
+ position,
224
+ rect,
225
+ height,
226
+ left
227
+ };
180
228
  }
181
-
182
- initDragging(ref: HTMLElement) {
183
- const ns = this.props.classPrefix;
184
- this.sortable.push(new Sortable(
185
- ref,
186
- {
187
- group: `nav-${this.id}`,
188
- animation: 150,
189
- handle: `.${ns}Nav-itemDrager`,
190
- ghostClass: `${ns}Nav-item--dragging`,
191
- onEnd: async (e: any) => {
192
- // 没有移动
193
- if (e.newIndex === e.oldIndex) {
194
- return;
195
- }
196
- const id = e.item.getAttribute('data-id');
197
- const parentNode = e.to
198
- if (
199
- e.newIndex < e.oldIndex &&
200
- e.oldIndex < parentNode.childNodes.length - 1
201
- ) {
202
- parentNode.insertBefore(e.item, parentNode.childNodes[e.oldIndex + 1]);
203
- } else if (e.oldIndex < parentNode.childNodes.length - 1) {
204
- parentNode.insertBefore(e.item, parentNode.childNodes[e.oldIndex]);
205
- } else {
206
- parentNode.appendChild(e.item);
207
- }
208
- const links = cloneDeep(this.props.links) as Link[];
209
- let parent = links;
210
- someTree(links, (item: Link, key, level, paths: Link[]) => {
211
- if (item.id === id) {
212
- const len = paths.length - 1;
213
- parent = (~len ? paths[len].children : links) as Link[];
214
- return true;
215
- }
216
- return false;
217
- });
218
- parent.splice(e.newIndex, 0, parent.splice(e.oldIndex, 1)[0]);
219
- const {saveOrderApi, env} = this.props;
220
- if (saveOrderApi && isEffectiveApi(saveOrderApi)) {
221
- await env.fetcher(saveOrderApi as SchemaApi, {data: links}, {method: 'post'});
222
- this.props.reload();
223
- } else {
224
- console.warn('请配置saveOrderApi');
225
- }
229
+ @autobind
230
+ updateDropIndicator(e: DragEvent) {
231
+ const {dragOnSameLevel} = this.props;
232
+ const target = e.target as HTMLElement; // a标签
233
+ const targetId = target.getAttribute('data-id') as string;
234
+ const targetDepth = Number(target.getAttribute('data-depth'));
235
+ if (dragOnSameLevel
236
+ && this.dragNode?.node.parentElement !== target.parentElement?.parentElement
237
+ ) {
238
+ this.setState({dropIndicator: undefined});
239
+ this.dropInfo = null;
240
+ return;
241
+ }
242
+ this.dropInfo = this.getDropInfo(e, targetId, targetDepth);
243
+ let {position, rect, dragLink, height, left} = this.dropInfo;
244
+ if (targetId === dragLink?.__id) {
245
+ this.setState({dropIndicator: undefined});
246
+ this.dropInfo = null;
247
+ return;
248
+ }
249
+ const ul = (findDOMNode(this) as HTMLElement).firstChild as HTMLElement;
250
+ if (position === 'self') {
251
+ this.setState({
252
+ dropIndicator: {
253
+ top: rect.top - ul.getBoundingClientRect().top,
254
+ left,
255
+ width: ul.getBoundingClientRect().width - left,
256
+ height,
257
+ opacity: .2
226
258
  }
227
- }
228
- ));
259
+ });
260
+ } else {
261
+ this.setState({
262
+ dropIndicator: {
263
+ top: (position === 'bottom' ? rect.top + rect.height : rect.top) - ul.getBoundingClientRect().top,
264
+ left,
265
+ width: ul.getBoundingClientRect().width - left
266
+ }
267
+ });
268
+ }
269
+ }
270
+
271
+ @autobind
272
+ handleDragStart(link: Link) {
273
+ return (e: React.DragEvent) => {
274
+ e.stopPropagation();
275
+ const currentTarget = e.currentTarget as HTMLElement;
276
+ e.dataTransfer.effectAllowed = 'copyMove';
277
+ e.dataTransfer.setDragImage(currentTarget, 0, 0);
278
+ this.dragNode = {
279
+ node: currentTarget,
280
+ link: link
281
+ };
282
+ this.dropInfo = null;
283
+ this.startPoint = {
284
+ x: e.clientX,
285
+ y: e.clientY
286
+ };
287
+ currentTarget.addEventListener('dragend', this.handleDragEnd);
288
+ document.body.addEventListener('dragover', this.handleDragOver);
289
+ };
290
+ }
291
+
292
+ @autobind
293
+ handleDragOver(e: DragEvent) {
294
+ e.preventDefault();
295
+ e.stopPropagation();
296
+ if (!this.dragNode) {
297
+ return;
298
+ }
299
+ const target = e.target as HTMLElement;
300
+ const id = target.getAttribute('data-id');
301
+ if (!id) {
302
+ return;
303
+ }
304
+ this.updateDropIndicator(e);
305
+ }
306
+
307
+ @autobind
308
+ handleDragEnd(e: DragEvent) {
309
+ e.preventDefault();
310
+ e.stopPropagation();
311
+ this.setState({
312
+ dropIndicator: undefined
313
+ });
314
+ const currentTarget = e.currentTarget as HTMLElement;
315
+ const id = currentTarget.getAttribute('data-id');
316
+ let nodeId = this.dropInfo?.nodeId;
317
+ if (!this.dropInfo || !nodeId || id === nodeId) {
318
+ return;
319
+ }
320
+ currentTarget.removeEventListener('dragend', this.handleDragEnd);
321
+ document.body.removeEventListener('dragover', this.handleDragOver);
322
+
323
+ this.props.onDragUpdate?.(this.dropInfo);
324
+ this.dragNode = null;
325
+ this.dropInfo = null;
229
326
  }
230
327
 
231
328
  renderItem(link: Link, index: number, depth = 1) {
@@ -242,37 +339,36 @@ export class Navigation extends React.Component<
242
339
  itemActions,
243
340
  draggable,
244
341
  links,
245
- badge: defaultBadge
342
+ itemBadge,
343
+ data: defaultData
246
344
  } = this.props;
247
345
  const hasSub =
248
346
  (link.defer && !link.loaded) || (link.children && link.children.length);
249
- const id = guid();
250
- link.id = id;
251
- const badge = defaultBadge ? Object.assign(defaultBadge, link.badge) : link.badge;
252
347
  return (
253
348
  <li
254
- key={index}
349
+ key={link.__id}
350
+ data-id={link.__id}
255
351
  className={cx('Nav-item', link.className, {
256
352
  'is-disabled': disabled || link.disabled || link.loading,
257
353
  'is-active': isActive,
258
354
  'is-unfolded': link.unfolded,
259
355
  'has-sub': hasSub
260
356
  })}
261
- data-id={id}
357
+ onDragStart={this.handleDragStart(link)}
262
358
  >
263
- <Badge classnames={cx} badge={badge} data={link}>
359
+ <Badge classnames={cx} badge={itemBadge} data={createObject(defaultData, link)}>
264
360
  <a
361
+ data-id={link.__id}
362
+ data-depth={depth}
265
363
  onClick={this.handleClick.bind(this, link)}
266
364
  style={{paddingLeft: depth * (parseInt(indentSize as any, 10) ?? 24)}}
267
365
  >
268
366
  {!disabled && draggable && links && links.length > 1 ? (
269
- <div className={cx('Nav-itemDrager')} >
270
- <a
271
- key="drag"
272
- data-position="bottom"
273
- >
274
- <Icon icon="drag-bar" className="icon" />
275
- </a>
367
+ <div className={cx('Nav-itemDrager')}
368
+ draggable
369
+ onMouseDown={e => {this.toggleLink(link, true); e.stopPropagation()}}
370
+ >
371
+ <Icon icon="drag-bar" className="icon" />
276
372
  </div>
277
373
  ) : null}
278
374
  {link.loading ? (
@@ -302,12 +398,12 @@ export class Navigation extends React.Component<
302
398
  itemActions
303
399
  ? <div className={cx('Nav-item-atcions')}>
304
400
  {
305
- render('inline', itemActions, {data: link})
401
+ render('inline', itemActions, {data: createObject(defaultData, link)})
306
402
  }
307
403
  </div> : null
308
404
  }
309
405
  {Array.isArray(link.children) && link.children.length ? (
310
- <ul className={cx('Nav-subItems')} ref={this.dragRefFn}>
406
+ <ul className={cx('Nav-subItems')}>
311
407
  {link.children.map((link, index) =>
312
408
  this.renderItem(link, index, depth + 1)
313
409
  )}
@@ -320,18 +416,21 @@ export class Navigation extends React.Component<
320
416
 
321
417
  render(): JSX.Element {
322
418
  const {className, stacked, classnames: cx, links, loading} = this.props;
323
-
419
+ const {dropIndicator} = this.state;
324
420
  return (
325
- <ul
326
- className={cx('Nav', className, stacked ? 'Nav--stacked' : 'Nav--tabs')}
327
- ref={this.dragRefFn}
328
- >
329
- {Array.isArray(links)
330
- ? links.map((item, index) => this.renderItem(item, index))
331
- : null}
332
-
333
- <Spinner show={!!loading} overlay icon="reload" />
334
- </ul>
421
+ <div className={cx('Nav')}>
422
+ <ul className={cx('Nav-list', className, stacked ? 'Nav-list--stacked' : 'Nav-list--tabs')}>
423
+ {Array.isArray(links)
424
+ ? links.map((item, index) => this.renderItem(item, index))
425
+ : null}
426
+
427
+ <Spinner show={!!loading} overlay icon="reload" />
428
+ </ul>
429
+ {(dropIndicator
430
+ ? <div className={cx('Nav-dropIndicator')} style={dropIndicator} />
431
+ : null
432
+ )}
433
+ </div>
335
434
  );
336
435
  }
337
436
  }
@@ -380,7 +479,8 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
380
479
  link.hasOwnProperty('to') &&
381
480
  env &&
382
481
  env.isCurrentUrl(filter(link.to as string, data))
383
- ))
482
+ )),
483
+ __id: guid()
384
484
  };
385
485
 
386
486
  item.unfolded =
@@ -444,6 +544,7 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
444
544
  super(props);
445
545
  this.toggleLink = this.toggleLink.bind(this);
446
546
  this.handleSelect = this.handleSelect.bind(this);
547
+ this.dragUpdate = this.dragUpdate.bind(this);
447
548
  }
448
549
 
449
550
  componentDidMount() {
@@ -460,7 +561,7 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
460
561
  }
461
562
  }
462
563
 
463
- toggleLink(target: Link) {
564
+ toggleLink(target: Link, forceFold?: boolean) {
464
565
  const {config, updateConfig, deferLoad} = this.props;
465
566
 
466
567
  if (target.defer && !target.loaded) {
@@ -471,7 +572,7 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
471
572
  target === link
472
573
  ? {
473
574
  ...link,
474
- unfolded: !link.unfolded
575
+ unfolded: forceFold ? false : !link.unfolded
475
576
  }
476
577
  : link
477
578
  ),
@@ -480,6 +581,60 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
480
581
  }
481
582
  }
482
583
 
584
+ async dragUpdate(dropInfo: IDropInfo) {
585
+ let links = this.props.config;
586
+ const {nodeId, dragLink, position} = dropInfo;
587
+ if (dragLink) {
588
+ // 删除原节点
589
+ const sourceIdx = findTreeIndex(links, link => link.__id === dragLink.__id) as number[];
590
+ links = spliceTree(links, sourceIdx, 1);
591
+
592
+ if (position === 'self') {
593
+ // 插入到对应节点的children中
594
+ mapTree(links, (link) => {
595
+ if (link.__id === nodeId) {
596
+ if (!link.children) {
597
+ link.children = [];
598
+ }
599
+ link.children.push(dragLink);
600
+ }
601
+ return link;
602
+ })
603
+ } else {
604
+ // 找到需要插入的节点
605
+ const idx = findTreeIndex(links, link => link.__id === nodeId) as number[];
606
+ // 插入节点之后
607
+ if (position === 'bottom') {
608
+ idx.push(idx.pop() as number + 1);
609
+ }
610
+ links = spliceTree(links, idx, 0, dragLink);
611
+ }
612
+ }
613
+ this.props.updateConfig(links, 'update');
614
+ await this.saveOrder(mapTree(links, (link: Link) => {
615
+ // 清除内部加的字段
616
+ for (let key in link) {
617
+ if (/^__.*$/.test(key)) {
618
+ delete link[key];
619
+ }
620
+ }
621
+ return link;
622
+ }));
623
+ }
624
+
625
+ async saveOrder(links: Links) {
626
+ const {saveOrderApi, env, data, reload} = this.props;
627
+ if (saveOrderApi && isEffectiveApi(saveOrderApi)) {
628
+ await env.fetcher(saveOrderApi as SchemaApi,
629
+ createObject(data, {data: links}),
630
+ {method: 'post'}
631
+ );
632
+ reload();
633
+ } else {
634
+ env.alert('NAV saveOrderApi is required!');
635
+ }
636
+ }
637
+
483
638
  handleSelect(link: Link) {
484
639
  const {onSelect, env, data} = this.props;
485
640
  if (onSelect && onSelect(link) === false) {
@@ -500,7 +655,6 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
500
655
 
501
656
  render() {
502
657
  const {loading, config, deferLoad, updateConfig, ...rest} = this.props;
503
-
504
658
  return (
505
659
  <ThemedNavigation
506
660
  {...rest}
@@ -509,6 +663,7 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
509
663
  disabled={loading}
510
664
  onSelect={this.handleSelect}
511
665
  onToggle={this.toggleLink}
666
+ onDragUpdate={this.dragUpdate}
512
667
  />
513
668
  );
514
669
  }
@@ -36,6 +36,11 @@ export interface SparkLineSchema extends BaseSchema {
36
36
  */
37
37
  clickAction?: ActionSchema;
38
38
 
39
+ /**
40
+ * 空数据时显示的内容
41
+ */
42
+ placeholder?: string;
43
+
39
44
  // /**
40
45
  // * 线的转折是否要有圆角。默认为 2
41
46
  // */