yy-forms 1.0.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.
- package/.fatherrc.js +37 -0
- package/CHANGELOG.md +254 -0
- package/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.esm.js +4006 -0
- package/dist/index.js +4041 -0
- package/es/Provider.js +248 -0
- package/es/index.d.ts +145 -0
- package/es/index.js +44 -0
- package/es/settings/index.js +975 -0
- package/es/styles/atom.less +1134 -0
- package/es/styles/index.less +358 -0
- package/es/transformer/form-render.js +75 -0
- package/es/utils/context.js +3 -0
- package/es/utils/hooks.js +48 -0
- package/es/utils/index.js +706 -0
- package/es/utils/mapping.js +31 -0
- package/es/utils/serialize.js +276 -0
- package/es/widgets/htmlInput.js +20 -0
- package/es/widgets/idInput.js +23 -0
- package/es/widgets/index.js +5 -0
- package/es/widgets/jsonInput.js +24 -0
- package/es/widgets/list.js +24 -0
- package/es/widgets/percentSlider.js +89 -0
- package/package.json +53 -0
- package/src/Provider.jsx +239 -0
- package/src/components/Canvas/core/RenderChildren.jsx +18 -0
- package/src/components/Canvas/core/RenderField.jsx +129 -0
- package/src/components/Canvas/core/Wrapper.jsx +298 -0
- package/src/components/Canvas/core/Wrapper.less +57 -0
- package/src/components/Canvas/core/index.jsx +171 -0
- package/src/components/Canvas/index.jsx +178 -0
- package/src/components/Settings/GlobalSettings.jsx +48 -0
- package/src/components/Settings/ItemSettings.jsx +143 -0
- package/src/components/Settings/index.jsx +75 -0
- package/src/components/Settings/index.less +25 -0
- package/src/components/Sidebar/Element.jsx +80 -0
- package/src/components/Sidebar/Element.less +18 -0
- package/src/components/Sidebar/index.jsx +47 -0
- package/src/components/Sidebar/index.less +23 -0
- package/src/i18next/index.ts +14 -0
- package/src/i18next/locales/enUS.json +60 -0
- package/src/i18next/locales/resources.ts +7 -0
- package/src/i18next/locales/zhCN.json +3 -0
- package/src/index.d.ts +145 -0
- package/src/index.js +45 -0
- package/src/settings/index.js +1058 -0
- package/src/styles/atom.less +1134 -0
- package/src/styles/index.less +358 -0
- package/src/transformer/form-render.js +65 -0
- package/src/utils/context.js +4 -0
- package/src/utils/hooks.js +35 -0
- package/src/utils/index.js +678 -0
- package/src/utils/mapping.js +29 -0
- package/src/utils/serialize.js +368 -0
- package/src/widgets/htmlInput.jsx +24 -0
- package/src/widgets/idInput.jsx +27 -0
- package/src/widgets/index.js +6 -0
- package/src/widgets/jsonInput.jsx +29 -0
- package/src/widgets/list.jsx +28 -0
- package/src/widgets/percentSlider.jsx +74 -0
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
import deepClone from 'clone';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
|
|
4
|
+
function stringContains(str, text) {
|
|
5
|
+
return str.indexOf(text) > -1;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const isObject = a =>
|
|
9
|
+
stringContains(Object.prototype.toString.call(a), 'Object');
|
|
10
|
+
|
|
11
|
+
// '3' => true, 3 => true, undefined => false
|
|
12
|
+
export function isLooselyNumber(num) {
|
|
13
|
+
if (typeof num === 'number') return true;
|
|
14
|
+
if (typeof num === 'string') {
|
|
15
|
+
return !Number.isNaN(Number(num));
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isCssLength(str) {
|
|
21
|
+
if (typeof str !== 'string') return false;
|
|
22
|
+
return str.match(/^([0-9])*(%|px|rem|em)$/i);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 深度对比
|
|
26
|
+
export function isDeepEqual(param1, param2) {
|
|
27
|
+
if (param1 === undefined && param2 === undefined) return true;
|
|
28
|
+
else if (param1 === undefined || param2 === undefined) return false;
|
|
29
|
+
if (param1 === null && param2 === null) return true;
|
|
30
|
+
else if (param1 === null || param2 === null) return false;
|
|
31
|
+
else if (param1.constructor !== param2.constructor) return false;
|
|
32
|
+
|
|
33
|
+
if (param1.constructor === Array) {
|
|
34
|
+
if (param1.length !== param2.length) return false;
|
|
35
|
+
for (let i = 0; i < param1.length; i++) {
|
|
36
|
+
if (param1[i].constructor === Array || param1[i].constructor === Object) {
|
|
37
|
+
if (!isDeepEqual(param1[i], param2[i])) return false;
|
|
38
|
+
} else if (param1[i] !== param2[i]) return false;
|
|
39
|
+
}
|
|
40
|
+
} else if (param1.constructor === Object) {
|
|
41
|
+
if (Object.keys(param1).length !== Object.keys(param2).length) return false;
|
|
42
|
+
for (let i = 0; i < Object.keys(param1).length; i++) {
|
|
43
|
+
const key = Object.keys(param1)[i];
|
|
44
|
+
if (
|
|
45
|
+
param1[key] &&
|
|
46
|
+
typeof param1[key] !== 'number' &&
|
|
47
|
+
(param1[key].constructor === Array ||
|
|
48
|
+
param1[key].constructor === Object)
|
|
49
|
+
) {
|
|
50
|
+
if (!isDeepEqual(param1[key], param2[key])) return false;
|
|
51
|
+
} else if (param1[key] !== param2[key]) return false;
|
|
52
|
+
}
|
|
53
|
+
} else if (param1.constructor === String || param1.constructor === Number) {
|
|
54
|
+
return param1 === param2;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ----------------- schema 相关
|
|
60
|
+
|
|
61
|
+
// 合并propsSchema和UISchema。由于两者的逻辑相关性,合并为一个大schema能简化内部处理
|
|
62
|
+
export function combineSchema(propsSchema = {}, uiSchema = {}) {
|
|
63
|
+
const propList = getChildren(propsSchema);
|
|
64
|
+
const newList = propList.map(p => {
|
|
65
|
+
const { name } = p;
|
|
66
|
+
const { type, enum: options, properties, items } = p.schema;
|
|
67
|
+
const isObj = type === 'object' && properties;
|
|
68
|
+
const isArr = type === 'array' && items && !options; // enum + array 代表的多选框,没有sub
|
|
69
|
+
const ui = name && uiSchema[p.name];
|
|
70
|
+
if (!ui) {
|
|
71
|
+
return p;
|
|
72
|
+
}
|
|
73
|
+
// 如果是list,递归合并items
|
|
74
|
+
if (isArr) {
|
|
75
|
+
const newItems = combineSchema(items, ui.items || {});
|
|
76
|
+
return { ...p, schema: { ...p.schema, ...ui, items: newItems } };
|
|
77
|
+
}
|
|
78
|
+
// object递归合并整个schema
|
|
79
|
+
if (isObj) {
|
|
80
|
+
const newSchema = combineSchema(p.schema, ui);
|
|
81
|
+
return { ...p, schema: newSchema };
|
|
82
|
+
}
|
|
83
|
+
return { ...p, schema: { ...p.schema, ...ui } };
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const newObj = {};
|
|
87
|
+
newList.forEach(s => {
|
|
88
|
+
newObj[s.name] = s.schema;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const topLevelUi = {};
|
|
92
|
+
Object.keys(uiSchema).forEach(key => {
|
|
93
|
+
if (typeof key === 'string' && key.substring(0, 3) === 'ui:') {
|
|
94
|
+
topLevelUi[key] = uiSchema[key];
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
if (isEmpty(newObj)) {
|
|
98
|
+
return { ...propsSchema, ...topLevelUi };
|
|
99
|
+
}
|
|
100
|
+
return { ...propsSchema, ...topLevelUi, properties: newObj };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function isEmpty(obj) {
|
|
104
|
+
return Object.keys(obj).length === 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 获得propsSchema的children
|
|
108
|
+
function getChildren(schema) {
|
|
109
|
+
if (!schema) return [];
|
|
110
|
+
const {
|
|
111
|
+
// object
|
|
112
|
+
properties,
|
|
113
|
+
// array
|
|
114
|
+
items,
|
|
115
|
+
type,
|
|
116
|
+
} = schema;
|
|
117
|
+
if (!properties && !items) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
let schemaSubs = {};
|
|
121
|
+
if (type === 'object') {
|
|
122
|
+
schemaSubs = properties;
|
|
123
|
+
}
|
|
124
|
+
if (type === 'array') {
|
|
125
|
+
schemaSubs = items;
|
|
126
|
+
}
|
|
127
|
+
return Object.keys(schemaSubs).map(name => ({
|
|
128
|
+
schema: schemaSubs[name],
|
|
129
|
+
name,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 判断schema的值是是否是“函数”
|
|
134
|
+
// JSON无法使用函数值的参数,所以使用"{{...}}"来标记为函数,也可使用@标记,不推荐。
|
|
135
|
+
export function isFunction(func) {
|
|
136
|
+
if (typeof func === 'function') {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
if (typeof func === 'string' && func.substring(0, 1) === '@') {
|
|
140
|
+
return func.substring(1);
|
|
141
|
+
}
|
|
142
|
+
if (
|
|
143
|
+
typeof func === 'string' &&
|
|
144
|
+
func.substring(0, 2) === '{{' &&
|
|
145
|
+
func.substring(func.length - 2, func.length) === '}}'
|
|
146
|
+
) {
|
|
147
|
+
return func.substring(2, func.length - 2);
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 判断schema中是否有属性值是函数表达式
|
|
153
|
+
export function isFunctionSchema(schema) {
|
|
154
|
+
return Object.keys(schema).some(key => {
|
|
155
|
+
if (typeof schema[key] === 'function') {
|
|
156
|
+
return true;
|
|
157
|
+
} else if (typeof schema[key] === 'string') {
|
|
158
|
+
return isFunction(schema[key]);
|
|
159
|
+
} else if (typeof schema[key] === 'object') {
|
|
160
|
+
return isFunctionSchema(schema[key]);
|
|
161
|
+
} else {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 后面三个参数都是内部递归使用的,将schema的树形结构扁平化成一层, 每个item的结构
|
|
168
|
+
// {
|
|
169
|
+
// parent: '#',
|
|
170
|
+
// schema: ...,
|
|
171
|
+
// children: []
|
|
172
|
+
// }
|
|
173
|
+
export function flattenSchema(schema, name = '#', parent, result = {}) {
|
|
174
|
+
const _schema = deepClone(schema);
|
|
175
|
+
if (!_schema.$id) {
|
|
176
|
+
_schema.$id = name; // 给生成的schema添加一个唯一标识,方便从schema中直接读取
|
|
177
|
+
}
|
|
178
|
+
const children = [];
|
|
179
|
+
const isObj = _schema.type === 'object' && _schema.properties;
|
|
180
|
+
const isList =
|
|
181
|
+
_schema.type === 'array' && _schema.items && _schema.items.properties;
|
|
182
|
+
if (isObj) {
|
|
183
|
+
Object.entries(_schema.properties).forEach(([key, value]) => {
|
|
184
|
+
const uniqueName = name + '/' + key;
|
|
185
|
+
children.push(uniqueName);
|
|
186
|
+
flattenSchema(value, uniqueName, name, result);
|
|
187
|
+
});
|
|
188
|
+
delete _schema.properties;
|
|
189
|
+
}
|
|
190
|
+
if (isList) {
|
|
191
|
+
Object.entries(_schema.items.properties).forEach(([key, value]) => {
|
|
192
|
+
const uniqueName = name + '/' + key;
|
|
193
|
+
children.push(uniqueName);
|
|
194
|
+
flattenSchema(value, uniqueName, name, result);
|
|
195
|
+
});
|
|
196
|
+
delete _schema.items.properties;
|
|
197
|
+
}
|
|
198
|
+
if (_schema.type) {
|
|
199
|
+
result[name] = { parent, schema: _schema, children };
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const getKeyFromUniqueId = (uniqueId = '#') => {
|
|
205
|
+
const arr = uniqueId.split('/');
|
|
206
|
+
return arr[arr.length - 1];
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const changeKeyFromUniqueId = (uniqueId = '#', key = 'something') => {
|
|
210
|
+
const arr = uniqueId.split('/');
|
|
211
|
+
if (typeof key === 'string' || typeof key === 'number') {
|
|
212
|
+
arr[arr.length - 1] = key;
|
|
213
|
+
}
|
|
214
|
+
return arr.join('/');
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// final = true 用于最终的导出的输出
|
|
218
|
+
// 几种特例:
|
|
219
|
+
// 1. 删除时值删除了item,没有删除和parent的关联,也没有删除children,所以要在解析这步来兜住 (所有的解析都是)
|
|
220
|
+
// 2. 修改$id的情况, 修改的是schema内的$id, 解析的时候要把schema.$id 作为真正的id (final = true的解析)
|
|
221
|
+
export function idToSchema(flatten, id = '#', final = false) {
|
|
222
|
+
let schema = {};
|
|
223
|
+
const _item = flatten[id];
|
|
224
|
+
const item = deepClone(_item);
|
|
225
|
+
if (item) {
|
|
226
|
+
schema = { ...item.schema };
|
|
227
|
+
// 最终输出去掉 $id
|
|
228
|
+
if (final) {
|
|
229
|
+
schema.$id && delete schema.$id;
|
|
230
|
+
}
|
|
231
|
+
if (item.children.length > 0) {
|
|
232
|
+
item.children.forEach(child => {
|
|
233
|
+
let childId = child;
|
|
234
|
+
// TODO: 这个情况会出现吗?return会有问题吗?
|
|
235
|
+
if (!flatten[child]) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
// 最终输出将所有的 key 值改了
|
|
239
|
+
try {
|
|
240
|
+
if (final) {
|
|
241
|
+
childId = flatten[child].schema.$id;
|
|
242
|
+
}
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.error(error, 'catch');
|
|
245
|
+
}
|
|
246
|
+
const key = getKeyFromUniqueId(childId);
|
|
247
|
+
if (schema.type === 'object') {
|
|
248
|
+
if (!schema.properties) {
|
|
249
|
+
schema.properties = {};
|
|
250
|
+
}
|
|
251
|
+
schema.properties[key] = idToSchema(flatten, child, final);
|
|
252
|
+
}
|
|
253
|
+
if (
|
|
254
|
+
schema.type === 'array' &&
|
|
255
|
+
schema.items &&
|
|
256
|
+
schema.items.type === 'object'
|
|
257
|
+
) {
|
|
258
|
+
if (!schema.items.properties) {
|
|
259
|
+
schema.items.properties = {};
|
|
260
|
+
}
|
|
261
|
+
schema.items.properties[key] = idToSchema(flatten, child, final);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
} else {
|
|
265
|
+
if (schema.type === 'object' && !schema.properties) {
|
|
266
|
+
schema.properties = {};
|
|
267
|
+
}
|
|
268
|
+
if (
|
|
269
|
+
schema.type === 'array' &&
|
|
270
|
+
schema.items &&
|
|
271
|
+
schema.items.type === 'object' &&
|
|
272
|
+
!schema.items.properties
|
|
273
|
+
) {
|
|
274
|
+
schema.items.properties = {};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return schema;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export const copyItem = (flatten, $id, getId) => {
|
|
282
|
+
let newFlatten = { ...flatten };
|
|
283
|
+
try {
|
|
284
|
+
const item = flatten[$id];
|
|
285
|
+
const newId = getId($id);
|
|
286
|
+
const siblings = newFlatten[item.parent].children;
|
|
287
|
+
const idx = siblings.findIndex(x => x === $id);
|
|
288
|
+
siblings.splice(idx + 1, 0, newId);
|
|
289
|
+
newFlatten[newId] = deepClone(newFlatten[$id]);
|
|
290
|
+
newFlatten[newId].schema.$id = newId;
|
|
291
|
+
return [newFlatten, newId];
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error(error, 'catcherror');
|
|
294
|
+
return [flatten, $id];
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// Left 点击添加 item
|
|
299
|
+
export const addItem = ({
|
|
300
|
+
selected,
|
|
301
|
+
name,
|
|
302
|
+
schema,
|
|
303
|
+
flatten,
|
|
304
|
+
fixedName,
|
|
305
|
+
getId,
|
|
306
|
+
}) => {
|
|
307
|
+
let _selected = selected || '#';
|
|
308
|
+
let newId;
|
|
309
|
+
// string第一个是0,说明点击了object、list的里侧
|
|
310
|
+
if ((_selected && _selected[0] === '0') || _selected === '#') {
|
|
311
|
+
const newFlatten = { ...flatten };
|
|
312
|
+
try {
|
|
313
|
+
let oldId = _selected.substring(1);
|
|
314
|
+
newId = _selected === '#' ? `#/` : `${oldId}/`;
|
|
315
|
+
if (!fixedName) {
|
|
316
|
+
newId += getId(name);
|
|
317
|
+
} else {
|
|
318
|
+
newId += name;
|
|
319
|
+
}
|
|
320
|
+
if (_selected === '#') {
|
|
321
|
+
oldId = '#';
|
|
322
|
+
}
|
|
323
|
+
const siblings = newFlatten[oldId].children;
|
|
324
|
+
siblings.push(newId);
|
|
325
|
+
const newItem = {
|
|
326
|
+
parent: oldId,
|
|
327
|
+
schema: { ...schema, $id: newId },
|
|
328
|
+
data: undefined,
|
|
329
|
+
children: [],
|
|
330
|
+
};
|
|
331
|
+
newFlatten[newId] = newItem;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error(error, 'catch');
|
|
334
|
+
}
|
|
335
|
+
return { newId, newFlatten };
|
|
336
|
+
}
|
|
337
|
+
const _name = fixedName ? name : getId(name);
|
|
338
|
+
const idArr = selected.split('/');
|
|
339
|
+
idArr.pop();
|
|
340
|
+
idArr.push(_name);
|
|
341
|
+
newId = idArr.join('/');
|
|
342
|
+
const newFlatten = { ...flatten };
|
|
343
|
+
try {
|
|
344
|
+
const item = newFlatten[selected];
|
|
345
|
+
const siblings = newFlatten[item.parent].children;
|
|
346
|
+
const idx = siblings.findIndex(x => x === selected);
|
|
347
|
+
siblings.splice(idx + 1, 0, newId);
|
|
348
|
+
const newItem = {
|
|
349
|
+
parent: item.parent,
|
|
350
|
+
schema: { ...schema, $id: newId },
|
|
351
|
+
data: undefined,
|
|
352
|
+
children: [],
|
|
353
|
+
};
|
|
354
|
+
newFlatten[newId] = newItem;
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error(error);
|
|
357
|
+
}
|
|
358
|
+
return { newId, newFlatten };
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// position 代表 drop 在元素的哪里: 'up' 上 'down' 下 'inside' 内部
|
|
362
|
+
export const dropItem = ({ dragId, dragItem, dropId, position, flatten }) => {
|
|
363
|
+
const _position = dropId === '#' ? 'inside' : position;
|
|
364
|
+
let newFlatten = { ...flatten };
|
|
365
|
+
// 会动到三块数据,dragItem, dragParent, dropParent. 其中dropParent可能就是dropItem(inside的情况)
|
|
366
|
+
if (dragItem) {
|
|
367
|
+
newFlatten[dragId] = dragItem;
|
|
368
|
+
}
|
|
369
|
+
const _dragItem = dragItem || newFlatten[dragId];
|
|
370
|
+
|
|
371
|
+
const dropItem = newFlatten[dropId];
|
|
372
|
+
let dropParent = dropItem;
|
|
373
|
+
if (_position !== 'inside') {
|
|
374
|
+
const parentId = dropItem.parent;
|
|
375
|
+
dropParent = newFlatten[parentId];
|
|
376
|
+
}
|
|
377
|
+
// TODO: 这块的体验,现在这样兜底了,但是drag起一个元素了,应该让原本变空
|
|
378
|
+
if (dropId.indexOf(dragId) > -1) {
|
|
379
|
+
return [newFlatten, dragId];
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
let newId = dragId;
|
|
383
|
+
try {
|
|
384
|
+
const newParentId = dropParent.schema.$id;
|
|
385
|
+
newId = newId.replace(_dragItem.parent, newParentId);
|
|
386
|
+
} catch (error) {}
|
|
387
|
+
|
|
388
|
+
// dragParent 的 children 删除 dragId
|
|
389
|
+
try {
|
|
390
|
+
const dragParent = newFlatten[_dragItem.parent];
|
|
391
|
+
const idx = dragParent.children.indexOf(dragId);
|
|
392
|
+
if (idx > -1 && !dragItem) {
|
|
393
|
+
dragParent.children.splice(idx, 1);
|
|
394
|
+
}
|
|
395
|
+
} catch (error) {
|
|
396
|
+
console.error(error);
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
// dropParent 的 children 添加 dragId
|
|
400
|
+
const newChildren = dropParent.children || []; // 要考虑children为空,inside的情况
|
|
401
|
+
const idx = newChildren.indexOf(dropId);
|
|
402
|
+
switch (_position) {
|
|
403
|
+
case 'up':
|
|
404
|
+
newChildren.splice(idx, 0, dragId);
|
|
405
|
+
break;
|
|
406
|
+
case 'down':
|
|
407
|
+
newChildren.splice(idx + 1, 0, dragId);
|
|
408
|
+
break;
|
|
409
|
+
default:
|
|
410
|
+
// inside 作为 default 情况
|
|
411
|
+
newChildren.push(dragId);
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
dropParent.children = newChildren;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
console.error(error);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
_dragItem.parent = dropParent.$id;
|
|
420
|
+
return [newFlatten, newId];
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// TODO: 没有考虑list的情况
|
|
424
|
+
export const dataToFlatten = (flatten, data) => {
|
|
425
|
+
if (!flatten || !data) return {};
|
|
426
|
+
Object.entries(flatten).forEach(([id, item]) => {
|
|
427
|
+
const branchData = getDataById(data, id);
|
|
428
|
+
flatten[id].data = branchData;
|
|
429
|
+
});
|
|
430
|
+
return flatten;
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
export const flattenToData = (flatten, id = '#') => {
|
|
434
|
+
try {
|
|
435
|
+
let result = flatten[id].data;
|
|
436
|
+
const ids = Object.keys(flatten);
|
|
437
|
+
const childrenIds = ids.filter(item => {
|
|
438
|
+
const lengthOfId = id.split('/').length;
|
|
439
|
+
const lengthOfChild = item.split('/').length;
|
|
440
|
+
return item.indexOf(id) > -1 && lengthOfChild > lengthOfId;
|
|
441
|
+
});
|
|
442
|
+
if (childrenIds && childrenIds.length > 0) {
|
|
443
|
+
const { type } = flatten[id].schema;
|
|
444
|
+
if (result === undefined) {
|
|
445
|
+
// TODO: 这个是简化的逻辑,在编辑器模型下,list和object都是object结构
|
|
446
|
+
if (type === 'object') {
|
|
447
|
+
result = {};
|
|
448
|
+
} else if (type === 'array') {
|
|
449
|
+
result = [{}];
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
childrenIds.forEach(c => {
|
|
453
|
+
const lengthOfId = id.split('/').length;
|
|
454
|
+
const lengthOfChild = c.split('/').length;
|
|
455
|
+
// 只比他长1,是直属的child
|
|
456
|
+
if (lengthOfChild === lengthOfId + 1) {
|
|
457
|
+
const cData = flattenToData(flatten, c);
|
|
458
|
+
const cKey = getKeyFromUniqueId(c);
|
|
459
|
+
if (cData === undefined) return result;
|
|
460
|
+
if (type === 'array') {
|
|
461
|
+
result[0][cKey] = cData;
|
|
462
|
+
} else {
|
|
463
|
+
result[cKey] = cData;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
return result;
|
|
469
|
+
} catch (error) {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// 例如当前item的id = '#/obj/input' propName: 'labelWidth' 往上一直找,直到找到第一个不是undefined的值
|
|
475
|
+
export const getParentProps = (propName, id, flatten) => {
|
|
476
|
+
try {
|
|
477
|
+
const item = flatten[id];
|
|
478
|
+
if (item.schema[propName] !== undefined) return item.schema[propName];
|
|
479
|
+
if (item && item.parent) {
|
|
480
|
+
const parentSchema = flatten[item.parent].schema;
|
|
481
|
+
if (parentSchema[propName] !== undefined) {
|
|
482
|
+
return parentSchema[propName];
|
|
483
|
+
} else {
|
|
484
|
+
return getParentProps(propName, item.parent, flatten);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
} catch (error) {
|
|
488
|
+
return undefined;
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
export function looseJsonParse(obj) {
|
|
493
|
+
return Function('"use strict";return (' + obj + ')')();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// 获得 propsSchema 的 children
|
|
497
|
+
export function getChildren2(schema) {
|
|
498
|
+
if (!schema) return [];
|
|
499
|
+
const {
|
|
500
|
+
// object
|
|
501
|
+
properties,
|
|
502
|
+
// array
|
|
503
|
+
items,
|
|
504
|
+
type,
|
|
505
|
+
} = schema;
|
|
506
|
+
if (!properties && !items) {
|
|
507
|
+
return [];
|
|
508
|
+
}
|
|
509
|
+
let schemaSubs = {};
|
|
510
|
+
if (type === 'object') {
|
|
511
|
+
schemaSubs = properties;
|
|
512
|
+
}
|
|
513
|
+
if (type === 'array') {
|
|
514
|
+
schemaSubs = items.properties;
|
|
515
|
+
}
|
|
516
|
+
return Object.keys(schemaSubs).map(name => ({
|
|
517
|
+
schema: schemaSubs[name],
|
|
518
|
+
name,
|
|
519
|
+
}));
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// 解析函数字符串值
|
|
523
|
+
// getDataById(formData, '#/a/b/c')
|
|
524
|
+
export function getDataById(object, path) {
|
|
525
|
+
path = castPath(path, object);
|
|
526
|
+
|
|
527
|
+
let index = 0;
|
|
528
|
+
const length = path.length;
|
|
529
|
+
|
|
530
|
+
while (object != null && index < length) {
|
|
531
|
+
const key = toKey(path[index++]);
|
|
532
|
+
if (Array.isArray(object) && typeof object[0] === 'object') {
|
|
533
|
+
object = key ? object[0][key] : object;
|
|
534
|
+
} else {
|
|
535
|
+
object = key ? object[key] : object;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return index && index == length ? object : undefined;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function castPath(value, object) {
|
|
543
|
+
if (Array.isArray(value)) {
|
|
544
|
+
return value;
|
|
545
|
+
}
|
|
546
|
+
return isKey(value, object) ? [value] : value.match(/([^\.\/\[\]#"']+)/g);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function toKey(value) {
|
|
550
|
+
if (typeof value === 'string') {
|
|
551
|
+
return value.replace(/^#\/?/, '');
|
|
552
|
+
}
|
|
553
|
+
const result = `${value}`;
|
|
554
|
+
return result == '0' && 1 / value == -INFINITY ? '-0' : result;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const reIsDeepProp = /#\/.+\//;
|
|
558
|
+
const reIsPlainProp = /^\w*$/;
|
|
559
|
+
|
|
560
|
+
function isKey(value, object) {
|
|
561
|
+
if (Array.isArray(value)) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
const type = typeof value;
|
|
565
|
+
if (type === 'number' || type === 'boolean' || value == null) {
|
|
566
|
+
return true;
|
|
567
|
+
}
|
|
568
|
+
return (
|
|
569
|
+
reIsPlainProp.test(value) ||
|
|
570
|
+
!reIsDeepProp.test(value) ||
|
|
571
|
+
(object != null && value in Object(object))
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export const oldSchemaToNew = schema => {
|
|
576
|
+
if (schema && schema.propsSchema) {
|
|
577
|
+
const { propsSchema, ...rest } = schema;
|
|
578
|
+
return { schema: propsSchema, ...rest };
|
|
579
|
+
}
|
|
580
|
+
if (schema && schema.schema) {
|
|
581
|
+
return schema.schema;
|
|
582
|
+
}
|
|
583
|
+
if (schema && schema.type === 'object') {
|
|
584
|
+
return schema;
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
type: 'object',
|
|
588
|
+
properties: {},
|
|
589
|
+
...schema,
|
|
590
|
+
};
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
export const newSchemaToOld = setting => {
|
|
594
|
+
if (setting && setting.schema) {
|
|
595
|
+
const { schema, ...rest } = setting;
|
|
596
|
+
return { propsSchema: schema, ...rest };
|
|
597
|
+
}
|
|
598
|
+
return setting;
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
export const schemaToState = value => {
|
|
602
|
+
const schema = oldSchemaToNew(value);
|
|
603
|
+
const frProps = Object.keys(schema).reduce((rst, cur) => {
|
|
604
|
+
if (['type', 'properties'].includes(cur)) return rst;
|
|
605
|
+
return { ...rst, [cur]: schema[cur] };
|
|
606
|
+
}, {});
|
|
607
|
+
const isNewVersion = !(value && value.propsSchema);
|
|
608
|
+
|
|
609
|
+
return {
|
|
610
|
+
schema,
|
|
611
|
+
frProps,
|
|
612
|
+
formData: schema.formData || {},
|
|
613
|
+
isNewVersion,
|
|
614
|
+
};
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
export function defaultGetValueFromEvent(valuePropName, ...args) {
|
|
618
|
+
const event = args[0];
|
|
619
|
+
if (event && event.target && valuePropName in event.target) {
|
|
620
|
+
return event.target[valuePropName];
|
|
621
|
+
}
|
|
622
|
+
return event;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export const transformProps = props => {
|
|
626
|
+
const { onChange, value, defaultValue, schema: ownSchema, ...rest } = props;
|
|
627
|
+
const schema = { ...ownSchema };
|
|
628
|
+
const { trigger, valuePropName } = schema || {};
|
|
629
|
+
const controlProps = {};
|
|
630
|
+
let _valuePropName = 'value';
|
|
631
|
+
const _value = value === undefined ? defaultValue : value;
|
|
632
|
+
if (valuePropName && typeof valuePropName === 'string') {
|
|
633
|
+
_valuePropName = valuePropName;
|
|
634
|
+
controlProps[valuePropName] = _value;
|
|
635
|
+
} else {
|
|
636
|
+
controlProps.value = _value;
|
|
637
|
+
}
|
|
638
|
+
const _onChange = (...args) => {
|
|
639
|
+
const newValue = defaultGetValueFromEvent(_valuePropName, ...args);
|
|
640
|
+
onChange(newValue);
|
|
641
|
+
};
|
|
642
|
+
if (trigger && typeof trigger === 'string') {
|
|
643
|
+
controlProps[trigger] = _onChange;
|
|
644
|
+
} else {
|
|
645
|
+
controlProps.onChange = _onChange;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// TODO: 之后 ui:xx 会舍去
|
|
649
|
+
const usefulPropsFromSchema = {
|
|
650
|
+
disabled: schema.disabled || schema['ui:disabled'],
|
|
651
|
+
readOnly: schema.readOnly || schema['ui:readonly'],
|
|
652
|
+
// hidden: schema.hidden || schema['ui:hidden'],
|
|
653
|
+
// $options: schema.options || schema['ui:options'],
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
const _props = {
|
|
657
|
+
...controlProps,
|
|
658
|
+
schema,
|
|
659
|
+
...usefulPropsFromSchema,
|
|
660
|
+
...rest,
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
return _props;
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
export const mergeInOrder = (...args) => {
|
|
667
|
+
return args.reduce((result, current) => {
|
|
668
|
+
if (!current) return result;
|
|
669
|
+
return Object.keys(current).reduce((rst, key) => {
|
|
670
|
+
if (rst[key]) delete rst[key];
|
|
671
|
+
return { ...rst, [key]: current[key] };
|
|
672
|
+
}, result);
|
|
673
|
+
}, {});
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
export const defaultGetId = name => {
|
|
677
|
+
return `${name}_${nanoid(6)}`;
|
|
678
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function getWidgetName(schema, _mapping) {
|
|
2
|
+
const { type, format, enum: enums, readonly } = schema;
|
|
3
|
+
|
|
4
|
+
// 如果已经注明了渲染widget,那最好
|
|
5
|
+
if (schema['widget']) {
|
|
6
|
+
return schema['widget'];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const list = [];
|
|
10
|
+
if (readonly) {
|
|
11
|
+
list.push(`${type}?readonly`);
|
|
12
|
+
list.push('*?readonly');
|
|
13
|
+
}
|
|
14
|
+
if (enums) {
|
|
15
|
+
list.push(`${type}?enum`);
|
|
16
|
+
// array 默认使用list,array?enum 默认使用checkboxes,*?enum 默认使用select
|
|
17
|
+
list.push('*?enum');
|
|
18
|
+
}
|
|
19
|
+
if (format) {
|
|
20
|
+
list.push(`${type}:${format}`);
|
|
21
|
+
}
|
|
22
|
+
list.push(type); // 放在最后兜底,其他都不match时使用type默认的组件
|
|
23
|
+
let found = '';
|
|
24
|
+
list.some(item => {
|
|
25
|
+
found = _mapping[item];
|
|
26
|
+
return !!found;
|
|
27
|
+
});
|
|
28
|
+
return found;
|
|
29
|
+
}
|