@cloudbase/framework-plugin-low-code 0.7.30 → 0.7.33

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.
@@ -54,7 +54,7 @@ const handler = {<% handlers.forEach(h => {%>
54
54
 
55
55
  const dataBinds = {<% Object.entries(dataBinds).map(([id, widgetBinds])=>{%>
56
56
  <%= id %>: { <% Object.entries(widgetBinds).map(([prop, expr]) => { %>
57
- <%= prop %>: function (lists, forItems, event, $context) {const $for=forItems; return (
57
+ '<%= prop %>': function (lists, forItems, event, $context) {const $for=forItems; return (
58
58
  <%= expr === '' ? 'undefined': expr %>
59
59
  ); },<% }) %>
60
60
  },<%}) %>
@@ -28,7 +28,7 @@ const evtListeners = {<% Object.entries(eventHanlders).map(([handlerName, listen
28
28
  }
29
29
  const dataBinds = {<% Object.entries(dataBinds).map(([id, widgetBinds])=>{%>
30
30
  <%= id %>: { <% Object.entries(widgetBinds).map(([prop, expr]) => { %>
31
- <%= prop %>: function (lists, forItems, event, $context) {const $for = forItems; return (
31
+ '<%= prop %>': function (lists, forItems, event, $context) {const $for = forItems; return (
32
32
  <%= expr === '' ? 'undefined': expr %>
33
33
  ); },<% }) %>
34
34
  },<%}) %>
@@ -129,7 +129,7 @@ function getForList(compId, dataBinds, parentForItems, dataContext) {
129
129
 
130
130
  try {
131
131
  // 绑定了 for 变量,但计算值错误时,应当空数组兜底
132
- forList = dataBinds && dataBinds._waFor && (dataBinds._waFor(parentForItems, undefined, dataContext) || []);
132
+ forList = dataBinds?._waFor && (dataBinds._waFor(parentForItems, undefined, dataContext) || []);
133
133
  } catch (e) {
134
134
  // 计算值出错则使用空数组兜底
135
135
  forList = [];
@@ -226,7 +226,9 @@ function FieldWrapper({
226
226
  }, []);
227
227
 
228
228
  React.useLayoutEffect(() => {
229
- currentWidget._getInstanceRef = () => instanceRef;
229
+ if (currentWidget) {
230
+ currentWidget._getInstanceRef = () => instanceRef;
231
+ }
230
232
  }, [currentWidget, instanceRef]);
231
233
 
232
234
  if (!Array.isArray(staticResourceAttribute)) {
@@ -342,6 +344,7 @@ export function getComponentRenderList(props) {
342
344
  const forItems = {
343
345
  ...parentForItems,
344
346
  [compId]: item,
347
+ index: { ...parentForItems.index, [compId]: index },
345
348
  forIndexes: forItemsIndexes,
346
349
  };
347
350
  const {
@@ -376,7 +379,7 @@ export function getComponentRenderList(props) {
376
379
  );
377
380
 
378
381
  return (
379
- <ForContext.Provider key={index} value={forItems}>
382
+ <ForContext.Provider key={forItemData._key} value={forItems}>
380
383
  <FieldWrapper
381
384
  Field={Field}
382
385
  componentSchema={componentSchema}
@@ -4,6 +4,8 @@ import { ForContext, getComponentRenderList } from './FieldMiddleware/renderer';
4
4
  import { isScopeSlot } from '../utils/index';
5
5
  import { observer } from 'mobx-react-lite';
6
6
 
7
+ export const RenderCustractorContext = React.createContext(AppRender);
8
+
7
9
  export function getComponentChildren(component, context = {}) {
8
10
  const { properties } = component;
9
11
  if (!properties) {
@@ -64,7 +66,7 @@ function getRenderList(props) {
64
66
 
65
67
  // wrapperClass
66
68
  const containerEl = Object.values(properties)[0];
67
- if (containerEl && containerEl['x-props'] && className) {
69
+ if (containerEl?.['x-props'] && className) {
68
70
  let { classNameList = [] } = containerEl['x-props'];
69
71
 
70
72
  // 先替换掉先前计算出来的className部分
@@ -82,7 +84,7 @@ function getRenderList(props) {
82
84
  containerEl['x-props'].classNameList = Array.from(new Set([className, ...classNameList]));
83
85
  }
84
86
 
85
- if (xProps && xProps.sourceKey) {
87
+ if (xProps?.sourceKey) {
86
88
  const { sourceKey } = xProps;
87
89
  const Field = virtualFields[sourceKey];
88
90
  if (!Field) {
@@ -124,10 +126,11 @@ export function generateSlotMetaMap(componentSchema, context, options = {}) {
124
126
  type: isHOC ? 'HOC' : 'ELEMENT',
125
127
  node: isHOC
126
128
  ? (props) => {
129
+ const Render = React.useContext(RenderCustractorContext) || AppRender;
127
130
  let clonedScopeContext = cloneDeep(scopeContext);
128
131
  set(clonedScopeContext, `${componentSchema.key}.${key}`, props);
129
132
  return (
130
- <AppRender
133
+ <Render
131
134
  key={key}
132
135
  componentSchema={child}
133
136
  renderSlot={options?.renderSlot}
@@ -140,9 +143,10 @@ export function generateSlotMetaMap(componentSchema, context, options = {}) {
140
143
  );
141
144
  }
142
145
  : () => {
146
+ const Render = React.useContext(RenderCustractorContext) || AppRender;
143
147
  return (
144
148
  <ForContext.Provider value={forContext}>
145
- <AppRender
149
+ <Render
146
150
  key={key}
147
151
  componentSchema={child}
148
152
  renderSlot={options?.renderSlot}
@@ -168,3 +172,11 @@ export const AppRender = observer(function (props) {
168
172
  injectContext: {},
169
173
  });
170
174
  });
175
+
176
+ export function ComponentAppRender(props) {
177
+ return getRenderList({
178
+ ...props,
179
+ forContext: React.useContext(ForContext),
180
+ injectContext: {},
181
+ });
182
+ }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { observable, autorun, untracked } from 'mobx';
3
- import { remove } from 'lodash';
3
+ import { remove, set as lodashSet } from 'lodash';
4
4
  import { checkVisible } from '../../utils/index';
5
5
 
6
6
  export const WidgetsContext = React.createContext({ parent: null });
@@ -109,33 +109,73 @@ export function createWidgets(widgetProps, dataBinds, scopeContext = {}, context
109
109
  if (!curForNode.value) {
110
110
  return createSubTree(curForNode, {}, scopeContext, context);
111
111
  }
112
+ const { _waForKey } = curForNode.value;
113
+ const timer = {};
112
114
  const dispose = autorun(() => {
113
115
  let forList = [];
114
116
  try {
115
- forList = dataBinds[nodeId]._waFor(forItems, undefined, context);
117
+ clearTimeout(timer[nodeId]);
118
+ const list = dataBinds[nodeId]._waFor(forItems, undefined, context);
119
+ if (!Array.isArray(list)) {
120
+ timer[nodeId] = setTimeout(() => {
121
+ console.warn(nodeId, 'For 循环绑定的数据并不是数组,请检查');
122
+ }, 1000);
123
+ } else {
124
+ forList = list;
125
+ }
116
126
  } catch (e) {
117
- console.warn('waFor error', e);
118
- }
119
-
120
- if (!Array.isArray(forList)) {
121
- forList = [];
122
- console.warn(nodeId, 'For 循环绑定的数据并不是数组,请检查');
127
+ timer[nodeId] = setTimeout(() => {
128
+ console.error('waFor error', e);
129
+ }, 1000);
123
130
  }
124
131
 
125
132
  // 让 forList 进行监听
126
133
  forList.forEach(() => {});
127
134
  untracked(() => {
128
- disposeWidgets(parentLevelWidgets[curForNode.id]);
135
+ // dispose widgets before reused instead
136
+ // disposeWidgets(parentLevelWidgets[curForNode.id]);
137
+
138
+ const exsitMap = forList.reduce((map, item) => {
139
+ if (item?.[_waForKey]) {
140
+ map[item[_waForKey]] = true;
141
+ }
142
+ return map;
143
+ }, {});
144
+ const forWidgets = parentLevelWidgets?.[nodeId];
145
+ const existedWidgetIndex = [];
146
+ const extraWidgetsIndex = [];
147
+ const extraWidgets = [];
148
+ forWidgets.forEach((widget, index) => {
149
+ if (exsitMap[widget._key]) {
150
+ existedWidgetIndex.push(index);
151
+ // need to use uqique key
152
+ exsitMap[widget._key] = undefined;
153
+ } else {
154
+ extraWidgetsIndex.push(index);
155
+ }
156
+ });
157
+ const extraWidgetsIndexMap = extraWidgetsIndex.reduce((map, item) => {
158
+ map[item] = true;
159
+ extraWidgets.push(forWidgets[item]);
160
+ return map;
161
+ }, {});
129
162
 
130
163
  // clean nodes of previouse for run
131
164
  dfsTree(curForNode, (node) => {
132
165
  const arr = parentLevelWidgets[node.id];
133
- arr.splice(0, arr.length);
134
- parentWidget && remove(parentWidget.children, ({ id }) => id === node.id);
166
+ remove(arr, (_, index) => {
167
+ return extraWidgetsIndexMap[index];
168
+ });
169
+ });
170
+
171
+ // 清理根 for 的 autorun, 并递归清理子节点
172
+ extraWidgets.map((w) => {
173
+ disposeWidgets([w]);
174
+ parentWidget && remove(parentWidget.children, ({ id }) => id === nodeId);
135
175
  });
136
176
 
137
177
  forList.forEach((item, index) => {
138
- const subForItems = { ...forItems, [nodeId]: item };
178
+ const subForItems = { ...forItems, [nodeId]: item, index: { ...forItems.index, [nodeId]: index } };
139
179
  createSubTree(curForNode, subForItems, scopeContext, context);
140
180
  });
141
181
 
@@ -150,80 +190,122 @@ export function createWidgets(widgetProps, dataBinds, scopeContext = {}, context
150
190
  const widgets = {};
151
191
 
152
192
  // traverse down the tree to set all widgets
153
- dfsTree(curForNode, (node, parentNode) => {
193
+ dfsTree(curForNode, (node, parentNode, cache) => {
194
+ const parentForWidgetArr = parentLevelWidgets?.[node.id] || [];
195
+ const { _waForKey } = node.value;
196
+ const key = subForItems[node.id]?.[_waForKey];
197
+ const index = cache[parentNode?.id]
198
+ ? cache[parentNode.id].index
199
+ : parentForWidgetArr.findIndex((widget) => key && widget._key === key);
200
+
201
+ const existedWidget = index !== -1 ? parentForWidgetArr[index] : null;
202
+
203
+ if (existedWidget) {
204
+ cache[node.id] = {
205
+ index,
206
+ };
207
+ }
208
+
154
209
  if (node.forCount === curForNode.forCount) {
155
210
  // Leaf node
156
- const w = observable(widgetProps[node.id]);
157
- w.id = node.id;
158
- if (node === curForNode) {
159
- w._disposers = [];
160
- }
161
- widgets[node.id] = w;
162
- w.findWidgets = (type, includeInvisibleDescendants) =>
163
- findWidgets(w, w.widgetType, type, includeInvisibleDescendants);
164
- w.getWidgetsByType = (type, includeInvisibleDescendants) =>
165
- w.findWidgets((currentWidget) => currentWidget.widgetType === type, includeInvisibleDescendants);
166
- w.getOwnerWidget = () => null; // 寻找父widget,默认返回null, 后续会覆写
167
- w._getInstanceRef = () => null; // 默认初始值
168
- Object.defineProperty(w, '_methods', {
169
- get() {
170
- const instance = this._getInstanceRef();
171
- return instance?.current?.methods;
172
- },
173
- });
174
- // 提供一个给 Node 挂载 API 的方式
175
- untracked(() => {
176
- w.extends = (name, fnOrData) =>
177
- Object.defineProperty(w, name, {
178
- value: fnOrData,
179
- writable: true,
211
+ let w = existedWidget;
212
+
213
+ if (!existedWidget) {
214
+ w = observable(widgetProps[node.id]);
215
+ w.id = node.id;
216
+ w._key = key;
217
+ if (node === curForNode) {
218
+ w._disposers = [];
219
+ }
220
+ widgets[node.id] = w;
221
+ // 提供一个给 Node 挂载 API 的方式
222
+ untracked(() => {
223
+ w.findWidgets = (type, includeInvisibleDescendants) =>
224
+ findWidgets(w, w.widgetType, type, includeInvisibleDescendants);
225
+ w.getWidgetsByType = (type, includeInvisibleDescendants) =>
226
+ w.findWidgets((currentWidget) => currentWidget.widgetType === type, includeInvisibleDescendants);
227
+ w.getOwnerWidget = () => null; // 寻找父widget,默认返回null, 后续会覆写
228
+ w._getInstanceRef = () => null; // 默认初始值
229
+ Object.defineProperty(w, '_methods', {
230
+ get() {
231
+ const instance = this._getInstanceRef();
232
+ return instance?.current?.methods;
233
+ },
180
234
  });
181
- });
182
- w.children = [];
183
- const parent = parentNode ? widgets[parentNode.id] : parentWidget;
184
- if (parent) {
185
- w.parent = parent;
186
- // 只有可显示 visible 的才存入 children 里
187
- if (checkVisible(w)) {
188
- parent.children.push(w);
235
+ w.extends = (name, fnOrData) =>
236
+ Object.defineProperty(w, name, {
237
+ value: fnOrData,
238
+ writable: true,
239
+ });
240
+ });
241
+ w.children = [];
242
+ const parent = parentNode ? widgets[parentNode.id] : parentWidget;
243
+ if (parent) {
244
+ w.parent = parent;
245
+ // 只有可显示 visible 的才存入 children 里
246
+ if (checkVisible(w)) {
247
+ parent.children.push(w);
248
+ }
189
249
  }
250
+ parentForWidgetArr.push?.(w);
251
+ } else {
252
+ disposeWidgets([existedWidget], true);
190
253
  }
191
- parentLevelWidgets && parentLevelWidgets[node.id].push(w);
192
-
254
+ widgets[node.id] = w;
193
255
  // Setup data binds
194
- Object.keys(dataBinds[node.id] || {}).map((prop) => {
195
- if (prop === '_waFor') {
196
- return;
197
- }
198
- function getBindData(options = {}) {
199
- let disposeError = false;
200
- const dispose = autorun(() => {
201
- try {
202
- // Computed data bind in the next tick since data bind may read widgets data
203
- w[prop] = dataBinds[node.id][prop](subForItems, undefined, context, scopeContext);
204
- disposeError = false;
205
- } catch (e) {
206
- options.showLog && console.error(e);
207
- retryQueue.push(getBindData);
208
- disposeError = true;
256
+ Object.keys(dataBinds[node.id] || {})
257
+ .sort((a, b) => {
258
+ return a.length - b.length > 0 ? 1 : -1;
259
+ })
260
+ .map((prop) => {
261
+ if (prop === '_waFor') {
262
+ return;
263
+ }
264
+ let timer = null;
265
+ function getBindData(options = {}) {
266
+ let disposeError = false;
267
+ const dispose = autorun(() => {
268
+ try {
269
+ clearTimeout(timer);
270
+ // Computed data bind in the next tick since data bind may read widgets data
271
+ const value = dataBinds[node.id][prop](subForItems, undefined, context, scopeContext);
272
+ const paths = prop.split('.').filter((key) => !!key);
273
+ if (paths.length > 1) {
274
+ // 一定要 untracked 不然爆栈了
275
+ untracked(() => lodashSet(w, prop, value));
276
+ } else {
277
+ // 普通 key 直接赋值
278
+ w[prop] = value;
279
+ }
280
+ disposeError = false;
281
+ } catch (e) {
282
+ if (options?.showLog) {
283
+ timer = setTimeout(() => {
284
+ console.warn(`Error computing data bind ${w.id}.${prop}`, e);
285
+ timer = null;
286
+ }, 1000);
287
+ }
288
+ retryQueue.push(getBindData);
289
+ disposeError = true;
290
+ }
291
+ });
292
+ if (!!disposeError && curForNode.id) {
293
+ widgets[curForNode.id]._disposers.push(dispose);
209
294
  }
210
- });
211
- if (!!disposeError && curForNode.id) {
212
- widgets[curForNode.id]._disposers.push(dispose);
213
295
  }
214
- }
215
- getBindData();
216
- });
217
- } else {
296
+ getBindData();
297
+ });
298
+ } else if (!existedWidget) {
218
299
  if (parentLevelWidgets) {
219
300
  const len = parentLevelWidgets[node.id].push([]);
220
301
  widgets[node.id] = parentLevelWidgets[node.id][len - 1];
221
302
  } else {
222
303
  widgets[node.id] = observable([]);
223
304
  }
305
+ } else {
306
+ widgets[node.id] = existedWidget;
224
307
  }
225
308
  });
226
-
227
309
  // run for of next level
228
310
  dfsTree(curForNode, (node, parentNode) => {
229
311
  if (node.forCount === curForNode.forCount + 1 && dataBinds[node.id]?._waFor) {
@@ -280,7 +362,7 @@ function createWidgetTree(widgets, dataBinds) {
280
362
  if (node.parent) {
281
363
  node.forCount = node.parent.forCount;
282
364
  }
283
- if (dataBinds[node.id] && dataBinds[node.id]._waFor) {
365
+ if (dataBinds[node.id]?._waFor) {
284
366
  node.forCount++;
285
367
  }
286
368
  node.children.map(addForCount);
@@ -289,19 +371,21 @@ function createWidgetTree(widgets, dataBinds) {
289
371
  return virtualRoot;
290
372
  }
291
373
 
292
- function dfsTree(node, fn, parent) {
293
- node.value && fn(node, parent);
294
- node.children.map((e) => dfsTree(e, fn, node.value ? node : null));
374
+ function dfsTree(node, fn, parent, cache = {}) {
375
+ node.value && fn(node, parent, cache);
376
+ node.children.map((e) => dfsTree(e, fn, node.value ? node : null, cache));
295
377
  }
296
378
 
297
379
  // dispose autorun
298
- function disposeWidgets(widgets = []) {
380
+ function disposeWidgets(widgets = [], noRecursive = false) {
299
381
  widgets.forEach((widget) => {
300
382
  const disposers = widget._disposers;
301
383
  if (disposers) {
302
384
  disposers.map((dispose) => dispose());
303
385
  disposers.splice(0, disposers.length);
304
386
  }
305
- disposeWidgets(widget.children);
387
+ if (!noRecursive) {
388
+ disposeWidgets(widget.children);
389
+ }
306
390
  });
307
391
  }
@@ -53,7 +53,9 @@ WEDA_CLOUD_SDK.setConfig({
53
53
  params.data.accessToken = accessToken;
54
54
  }
55
55
  } catch (e) {
56
- console.error('beforeCallFunction error', e);
56
+ if (app?.cloud?.currentUser?.userType === "externalUser" && e?.error === 'unauthenticated') {
57
+ console.error('beforeCallFunction error', e);
58
+ }
57
59
  }
58
60
  return params;
59
61
  },
@@ -1,9 +1,9 @@
1
1
  import * as React from "react";
2
2
  import { observer } from "mobx-react-lite";
3
- import { observable } from "mobx";
4
- import { get } from 'lodash'
3
+ import { observable, autorun, reaction, runInAction } from "mobx";
4
+ import { get } from 'lodash';
5
5
 
6
- import { AppRender } from "handlers/render";
6
+ import { ComponentAppRender as AppRender } from "handlers/render";
7
7
  import { createComputed } from "../../../../utils";
8
8
  import { createWidgets, retryDataBinds, WidgetsContext, resolveComponentProps } from 'handlers/utils'
9
9
  import getStateFn from "./lowcode/state.js";
@@ -37,11 +37,15 @@ class CompositeCompWrapper extends React.Component {
37
37
  $WEAPPS_COMP = {}
38
38
 
39
39
  componentDidUpdate() {
40
- const { data } = this.props
41
- for(let prop in data) {
42
- // 更新 propsData
43
- this.propsData[prop] = data[prop]
44
- }
40
+ runInAction(() => {
41
+ const { data } = this.props
42
+ for(let prop in data) {
43
+ // 更新 propsData
44
+ if (typeof data[prop] !== 'function') {
45
+ this.propsData[prop] = data[prop]
46
+ }
47
+ }
48
+ })
45
49
  }
46
50
 
47
51
 
@@ -56,9 +60,9 @@ class CompositeCompWrapper extends React.Component {
56
60
  });
57
61
  this.events = (<%= emitEvents %>).reduce((obj, trigger) => {
58
62
  obj[trigger] = (event) => {
59
- this.props.emit(trigger, event)
63
+ this.props.emit(trigger, event);
60
64
  };
61
- return obj
65
+ return obj;
62
66
  }, {});
63
67
  this.handler = this.$WEAPPS_COMP.handler = {
64
68
  <% handlersImports.forEach(handler => { %>
@@ -166,7 +170,9 @@ class CompositeCompWrapper extends React.Component {
166
170
  }
167
171
  }
168
172
 
173
+ CompositeCompWrapper.contextType = WidgetsContext
174
+
169
175
  export default observer((props, _ref) => (
170
- <CompositeCompWrapper {...props} forwardRef={_ref}></CompositeCompWrapper>
176
+ <CompositeCompWrapper {...props} forwardRef={_ref}></CompositeCompWrapper>
171
177
  ), { forwardRef: true });
172
178