cdui-js 1.0.13 → 1.0.14
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/build/css.ts +9 -18
- package/css/all.css +8 -3
- package/css/base.css +4 -0
- package/css/button.css +3 -0
- package/css/canlendar.css +1 -26
- package/css/carousel.css +0 -3
- package/css/combobox.css +5 -25
- package/css/datepicker.css +38 -0
- package/css/form.css +19 -0
- package/css/popup.css +33 -0
- package/css/textbox.css +5 -0
- package/{css → demo/css}/build.ts +1 -1
- package/{css → demo/css}/css.md +45 -4
- package/demo/icons/build.ts +17 -0
- package/{index.html → demo/index.html} +20 -2
- package/demo/src/App.tsx +15 -0
- package/demo/src/css/all.css +3 -0
- package/demo/src/css/atomic.css +935 -0
- package/demo/src/main.ts +10 -0
- package/demo/{pages → src/pages}/Canlendar.tsx +1 -1
- package/demo/src/pages/ComboBox.tsx +10 -0
- package/demo/src/pages/DatePicker.tsx +5 -0
- package/demo/src/pages/Form.tsx +66 -0
- package/{vite.config.ts → demo/vite.config.ts} +2 -2
- package/icons/backward.svg +2 -2
- package/icons/close.svg +3 -3
- package/icons/dropdown.svg +2 -2
- package/icons/forward.svg +2 -2
- package/package.json +4 -2
- package/src/components/Button.tsx +5 -0
- package/src/components/Canlendar.tsx +23 -45
- package/src/components/Carousel.tsx +13 -4
- package/src/components/CollapsiblePanel.tsx +2 -4
- package/src/components/ComboBox.tsx +50 -146
- package/src/components/DatePicker.tsx +91 -0
- package/src/components/Dialog.ts +1 -1
- package/src/components/Form.tsx +141 -418
- package/src/components/Icon.tsx +2 -1
- package/src/components/Popup.tsx +220 -0
- package/src/components/Pulldown.tsx +2 -3
- package/src/components/TextBox.tsx +8 -0
- package/src/dom.ts +55 -39
- package/src/http.ts +23 -19
- package/src/i18n/languages/en.json +3 -3
- package/src/index.ts +5 -1
- package/src/reactive.ts +9 -0
- package/demo/App.tsx +0 -31
- package/demo/main.ts +0 -7
- package/demo/pages/ComboBox.tsx +0 -10
- package/demo/pages/Form.tsx +0 -32
- package/icons/build.ts +0 -24
- /package/demo/{test.js → src/test.js} +0 -0
package/src/components/Form.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Form as i18n } from '../i18n';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { createContext, useContext, splitProps, onMount, combineClass } from '../reactive';
|
|
4
4
|
import { JSX } from '../jsx';
|
|
5
|
+
import { replaceTemplate } from '../template';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* 表单属性集
|
|
@@ -22,7 +23,7 @@ export interface FormItemProps {
|
|
|
22
23
|
/**
|
|
23
24
|
* 标签对齐方式(未设置则继承所属表单的对齐方式)
|
|
24
25
|
*/
|
|
25
|
-
align?: '' | 'left' | '
|
|
26
|
+
align?: '' | 'left' | 'top' | 'right';
|
|
26
27
|
/**
|
|
27
28
|
* 是否必填
|
|
28
29
|
*/
|
|
@@ -73,11 +74,6 @@ export interface ValidateTarget {
|
|
|
73
74
|
* 表单项
|
|
74
75
|
*/
|
|
75
76
|
item: FormItemProps;
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* 父表单数据
|
|
79
|
-
*/
|
|
80
|
-
parent?: ValidateTarget;
|
|
81
77
|
}
|
|
82
78
|
|
|
83
79
|
/**
|
|
@@ -94,7 +90,7 @@ export interface BaseValidateRule {
|
|
|
94
90
|
*
|
|
95
91
|
* @param target 校验目标
|
|
96
92
|
*/
|
|
97
|
-
onvalidate?(target: ValidateTarget): string | Promise<string>;
|
|
93
|
+
onvalidate?(target: ValidateTarget, form: HTMLFormElement): string | Promise<string>;
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
export interface BooleanValidateRule extends BaseValidateRule {
|
|
@@ -184,18 +180,6 @@ export interface ObjectValidateRule extends BaseValidateRule {
|
|
|
184
180
|
subRules?: ValidateRules;
|
|
185
181
|
}
|
|
186
182
|
|
|
187
|
-
export interface ArrayValidateRule extends BaseValidateRule {
|
|
188
|
-
/**
|
|
189
|
-
* 数组校验规则
|
|
190
|
-
*/
|
|
191
|
-
type: 'array';
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* 子项校验规则
|
|
195
|
-
*/
|
|
196
|
-
itemRules: ValidateRules;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
183
|
/**
|
|
200
184
|
* 校验规则
|
|
201
185
|
*/
|
|
@@ -204,8 +188,7 @@ export type ValidateRule =
|
|
|
204
188
|
| NumberValidateRule
|
|
205
189
|
| StringValidateRule
|
|
206
190
|
| DateValidateRule
|
|
207
|
-
| ObjectValidateRule
|
|
208
|
-
| ArrayValidateRule;
|
|
191
|
+
| ObjectValidateRule;
|
|
209
192
|
|
|
210
193
|
/**
|
|
211
194
|
* 校验规则集合
|
|
@@ -214,44 +197,39 @@ export interface ValidateRules {
|
|
|
214
197
|
[key: string]: ValidateRule;
|
|
215
198
|
}
|
|
216
199
|
|
|
217
|
-
const defaultContext = {
|
|
218
|
-
align: 'left',
|
|
219
|
-
width: '',
|
|
220
|
-
};
|
|
221
|
-
|
|
222
200
|
/**
|
|
223
201
|
* 表单上下文
|
|
224
202
|
*/
|
|
225
|
-
const FormContext = createContext();
|
|
203
|
+
const FormContext = createContext<Pick<FormItemProps, 'align' | 'labelWidth'>>();
|
|
226
204
|
|
|
227
|
-
const replaceError = (item: FormItemProps, error: string, value
|
|
205
|
+
const replaceError = (item: FormItemProps, error: string, value?: unknown) => {
|
|
228
206
|
let label = item.label;
|
|
229
207
|
|
|
230
|
-
|
|
208
|
+
error = error
|
|
231
209
|
.replace(/\$\{label\}/g, typeof label !== 'string' ? (label as HTMLElement).textContent : label)
|
|
232
|
-
.replace(/\$\{field\}/g, item.field)
|
|
233
|
-
|
|
210
|
+
.replace(/\$\{field\}/g, item.field);
|
|
211
|
+
|
|
212
|
+
if (value !== void 0) {
|
|
213
|
+
error = error.replace(/\$\{value\}/g, value as string);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return error;
|
|
234
217
|
};
|
|
235
218
|
|
|
236
219
|
const validateRange = (item: FormItemProps, rule: { min?: unknown; max?: unknown }, value: unknown) => {
|
|
237
220
|
let min = rule.min;
|
|
238
221
|
let max = rule.max;
|
|
239
|
-
let error;
|
|
240
222
|
|
|
241
|
-
if (
|
|
242
|
-
if (max
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
} else {
|
|
247
|
-
|
|
223
|
+
if (min != null) {
|
|
224
|
+
if (max != null) {
|
|
225
|
+
if (value < min || value > max) {
|
|
226
|
+
return replaceError(item, replaceTemplate(i18n.Between, { min, max }));
|
|
227
|
+
}
|
|
228
|
+
} else if (value < min) {
|
|
229
|
+
return replaceError(item, i18n.NotLessThan, min);
|
|
248
230
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
.replace(/\$\{min\}/g, min as string)
|
|
252
|
-
.replace(/\$\{max\}/g, max as string);
|
|
253
|
-
|
|
254
|
-
return false;
|
|
231
|
+
} else if (max != null && value > max) {
|
|
232
|
+
return replaceError(item, i18n.NotGreaterThan, max);
|
|
255
233
|
}
|
|
256
234
|
};
|
|
257
235
|
|
|
@@ -262,19 +240,17 @@ export const validateRules = {
|
|
|
262
240
|
number: (item: FormItemProps, rule: NumberValidateRule, value: unknown) => {
|
|
263
241
|
if (value || (value = +value) === 0) {
|
|
264
242
|
// 范围校验
|
|
265
|
-
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
243
|
+
return validateRange(item, rule, value);
|
|
268
244
|
}
|
|
269
245
|
},
|
|
270
246
|
|
|
271
247
|
string: (item: FormItemProps, rule: StringValidateRule, value: unknown) => {
|
|
272
|
-
let match;
|
|
273
|
-
|
|
274
248
|
if (value) {
|
|
249
|
+
let match, error;
|
|
250
|
+
|
|
275
251
|
// 范围校验
|
|
276
|
-
if (validateRange(item, rule, (value = '' + value))
|
|
277
|
-
return
|
|
252
|
+
if ((error = validateRange(item, rule, (value = '' + value)))) {
|
|
253
|
+
return error;
|
|
278
254
|
}
|
|
279
255
|
|
|
280
256
|
// 正则校验
|
|
@@ -282,13 +258,15 @@ export const validateRules = {
|
|
|
282
258
|
if (match instanceof Array) {
|
|
283
259
|
for (let i = 0, l = match.length; i < l; i++) {
|
|
284
260
|
if (!match[i].rule.test(value as string)) {
|
|
285
|
-
|
|
286
|
-
|
|
261
|
+
if ((error = replaceError(item, match[i].error, value))) {
|
|
262
|
+
return error;
|
|
263
|
+
}
|
|
287
264
|
}
|
|
288
265
|
}
|
|
289
266
|
} else if (!match.rule.test(value as string)) {
|
|
290
|
-
|
|
291
|
-
|
|
267
|
+
if ((error = replaceError(item, match.error, value))) {
|
|
268
|
+
return error;
|
|
269
|
+
}
|
|
292
270
|
}
|
|
293
271
|
}
|
|
294
272
|
}
|
|
@@ -308,8 +286,7 @@ export const validateRules = {
|
|
|
308
286
|
break;
|
|
309
287
|
|
|
310
288
|
default:
|
|
311
|
-
|
|
312
|
-
break;
|
|
289
|
+
return replaceError(item, i18n.NotDate, value);
|
|
313
290
|
}
|
|
314
291
|
}
|
|
315
292
|
|
|
@@ -318,40 +295,6 @@ export const validateRules = {
|
|
|
318
295
|
},
|
|
319
296
|
};
|
|
320
297
|
|
|
321
|
-
/**
|
|
322
|
-
* 校验规则
|
|
323
|
-
*
|
|
324
|
-
* @param item 表单校验
|
|
325
|
-
* @param rule 校验规则
|
|
326
|
-
* @param target 校验目标
|
|
327
|
-
*/
|
|
328
|
-
export const validateRule = async (rule: ValidateRule, target: ValidateTarget) => {
|
|
329
|
-
let type = rule && rule.type;
|
|
330
|
-
let item = target.item;
|
|
331
|
-
let value = target.value;
|
|
332
|
-
|
|
333
|
-
if (
|
|
334
|
-
item.required &&
|
|
335
|
-
(value == null || value === '' || (type === 'array' && (value as Array<unknown>).length === 0))
|
|
336
|
-
) {
|
|
337
|
-
target.item.error = replaceError(item, item.requiredError || i18n.Required, value);
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (rule) {
|
|
342
|
-
if (validateRules[type] && validateRules[type](item, rule, value) === false) {
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
if (rule.onvalidate && (item.error = await rule.onvalidate(target))) {
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// 清除错误信息
|
|
352
|
-
item.error = '';
|
|
353
|
-
};
|
|
354
|
-
|
|
355
298
|
/**
|
|
356
299
|
* 查找指定字段的规则
|
|
357
300
|
*
|
|
@@ -384,125 +327,119 @@ const findValue = (data: any, fields: string[]) => {
|
|
|
384
327
|
return data;
|
|
385
328
|
};
|
|
386
329
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
*/
|
|
390
|
-
const update = (parent: any, labelWidth: string) => {
|
|
391
|
-
let child = parent.firstChild;
|
|
392
|
-
let label;
|
|
330
|
+
const showError = (formItem: HTMLElement, error: string) => {
|
|
331
|
+
let dom = formItem.querySelector('.form-error');
|
|
393
332
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
333
|
+
if (dom) {
|
|
334
|
+
dom.textContent = error;
|
|
335
|
+
} else {
|
|
336
|
+
dom = document.createElement('div');
|
|
337
|
+
dom.className = 'form-error';
|
|
338
|
+
dom.textContent = error;
|
|
339
|
+
|
|
340
|
+
formItem.querySelector('.form-body').appendChild(dom);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const removeError = (formItem: HTMLElement) => {
|
|
345
|
+
let dom = formItem.querySelector('.form-error');
|
|
407
346
|
|
|
408
|
-
|
|
347
|
+
if (dom) {
|
|
348
|
+
dom.parentNode.removeChild(dom);
|
|
409
349
|
}
|
|
410
350
|
};
|
|
411
351
|
|
|
412
352
|
/**
|
|
413
|
-
*
|
|
353
|
+
* 校验规则
|
|
354
|
+
*
|
|
355
|
+
* @param rule 校验规则
|
|
356
|
+
* @param target 校验目标
|
|
357
|
+
* @param form 所属表单
|
|
414
358
|
*/
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
filter?: (target: ValidateTarget) => void | boolean,
|
|
421
|
-
parent?: ValidateTarget,
|
|
422
|
-
) => {
|
|
423
|
-
let errors = 0;
|
|
424
|
-
let child = body.firstChild;
|
|
359
|
+
export const validateRule = async (rule: ValidateRule, target: ValidateTarget, form: HTMLFormElement) => {
|
|
360
|
+
let type = rule && rule.type;
|
|
361
|
+
let item = target.item;
|
|
362
|
+
let value = target.value;
|
|
363
|
+
let error;
|
|
425
364
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
errors += await validate(child, child, child.rules || rules, child.data || {}, filter, parent);
|
|
430
|
-
} else if (!(child instanceof FormItem)) {
|
|
431
|
-
// 不是表单和表单项则递归处理
|
|
432
|
-
errors += await validateArray(host, child, rules, data, filter, parent);
|
|
365
|
+
if (rule) {
|
|
366
|
+
if (validateRules[type] && (error = validateRules[type](item, rule, value))) {
|
|
367
|
+
return error;
|
|
433
368
|
}
|
|
434
369
|
|
|
435
|
-
|
|
370
|
+
if (rule.onvalidate && (error = await rule.onvalidate(target, form))) {
|
|
371
|
+
return error;
|
|
372
|
+
}
|
|
436
373
|
}
|
|
437
|
-
|
|
438
|
-
return errors;
|
|
439
374
|
};
|
|
440
375
|
|
|
441
376
|
/**
|
|
442
377
|
* 校验
|
|
443
378
|
*/
|
|
444
379
|
const validate = async (
|
|
445
|
-
|
|
446
|
-
body: any,
|
|
380
|
+
form: HTMLFormElement,
|
|
447
381
|
rules: ValidateRules,
|
|
448
382
|
data: object,
|
|
449
383
|
filter?: (target: ValidateTarget) => void | boolean,
|
|
450
|
-
parent?: ValidateTarget,
|
|
451
384
|
) => {
|
|
452
|
-
let
|
|
453
|
-
let child =
|
|
454
|
-
let field, rule: ValidateRule;
|
|
385
|
+
let result = true;
|
|
386
|
+
let child = form.firstElementChild as any;
|
|
387
|
+
let field, rule: ValidateRule, item: FormItemProps;
|
|
455
388
|
|
|
456
389
|
while (child) {
|
|
457
390
|
// 表单项
|
|
458
|
-
if (
|
|
391
|
+
if ((item = child.FORM_ITEM)) {
|
|
392
|
+
let error;
|
|
393
|
+
|
|
459
394
|
// 有设置了字段且未隐藏
|
|
460
|
-
if (
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
value,
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
395
|
+
if (!item.hidden && (field = child.dataset.field)) {
|
|
396
|
+
// 必填
|
|
397
|
+
if (item.required) {
|
|
398
|
+
// 当前值
|
|
399
|
+
let value = findValue(data, field);
|
|
400
|
+
|
|
401
|
+
if (value == null || value === '') {
|
|
402
|
+
error = replaceError(item, item.requiredError || i18n.Required, value);
|
|
403
|
+
}
|
|
404
|
+
} else if ((rule = findRule(rules, (field = field.split('.'))))) {
|
|
405
|
+
// 当前值
|
|
406
|
+
let value = findValue(data, field);
|
|
407
|
+
// 校验目标
|
|
408
|
+
let target = {
|
|
409
|
+
data,
|
|
410
|
+
field,
|
|
411
|
+
value,
|
|
412
|
+
label: child.label,
|
|
413
|
+
item: child,
|
|
414
|
+
parent,
|
|
415
|
+
} as ValidateTarget;
|
|
416
|
+
|
|
417
|
+
// 没有过滤或符合过滤条件才校验
|
|
418
|
+
if (!filter || filter(target)) {
|
|
419
|
+
error = await validateRule(rule, target, form);
|
|
482
420
|
}
|
|
483
421
|
}
|
|
422
|
+
}
|
|
484
423
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
424
|
+
if (error) {
|
|
425
|
+
showError(child, error);
|
|
426
|
+
} else {
|
|
427
|
+
removeError(child);
|
|
428
|
+
}
|
|
429
|
+
} else if (child instanceof HTMLFormElement) {
|
|
430
|
+
// 子表单级联校验
|
|
431
|
+
child.api.validate(filter);
|
|
432
|
+
} else {
|
|
433
|
+
// 不是表单则递归
|
|
434
|
+
if (!(await validate(child, rules, data, filter))) {
|
|
435
|
+
result = false;
|
|
496
436
|
}
|
|
497
|
-
} else if (!(child instanceof Form)) {
|
|
498
|
-
// 不是表单
|
|
499
|
-
errors += await validate(host, child, rules, data, filter, parent);
|
|
500
437
|
}
|
|
501
438
|
|
|
502
|
-
child = child.
|
|
439
|
+
child = child.nextElementSibling;
|
|
503
440
|
}
|
|
504
441
|
|
|
505
|
-
return
|
|
442
|
+
return result;
|
|
506
443
|
};
|
|
507
444
|
|
|
508
445
|
/**
|
|
@@ -523,192 +460,27 @@ export const FormItem = (props?: JSX.HTMLAttributes<never> & FormItemProps) => {
|
|
|
523
460
|
'children',
|
|
524
461
|
]);
|
|
525
462
|
|
|
526
|
-
// /**
|
|
527
|
-
// * 属性值集合
|
|
528
|
-
// */
|
|
529
|
-
// protected readonly [PROPERTIES] = {
|
|
530
|
-
// /**
|
|
531
|
-
// * 字段名
|
|
532
|
-
// */
|
|
533
|
-
// field: '',
|
|
534
|
-
// /**
|
|
535
|
-
// * 标签宽度
|
|
536
|
-
// */
|
|
537
|
-
// labelWidth: '',
|
|
538
|
-
// /**
|
|
539
|
-
// * 必填错误信息
|
|
540
|
-
// */
|
|
541
|
-
// requiredError: '',
|
|
542
|
-
// /**
|
|
543
|
-
// * 错误信息
|
|
544
|
-
// */
|
|
545
|
-
// error: '',
|
|
546
|
-
// /**
|
|
547
|
-
// * html for
|
|
548
|
-
// */
|
|
549
|
-
// for: '',
|
|
550
|
-
// };
|
|
551
|
-
// /**
|
|
552
|
-
// * 关联的字段名(可使用 "." 表示嵌套字段,如:"a.b.c")
|
|
553
|
-
// */
|
|
554
|
-
// get field(): string {
|
|
555
|
-
// return this[PROPERTIES].field;
|
|
556
|
-
// }
|
|
557
|
-
// set field(value) {
|
|
558
|
-
// this[PROPERTIES].field = '' + value;
|
|
559
|
-
// }
|
|
560
|
-
// /**
|
|
561
|
-
// * 是否必填
|
|
562
|
-
// */
|
|
563
|
-
// get required(): boolean {
|
|
564
|
-
// return this.hasAttribute('required');
|
|
565
|
-
// }
|
|
566
|
-
// set required(value) {
|
|
567
|
-
// if (value) {
|
|
568
|
-
// this.setAttribute('required', '');
|
|
569
|
-
// } else {
|
|
570
|
-
// this.removeAttribute('required');
|
|
571
|
-
// }
|
|
572
|
-
// }
|
|
573
|
-
// /**
|
|
574
|
-
// * 必填校验信息
|
|
575
|
-
// */
|
|
576
|
-
// get requiredError(): string {
|
|
577
|
-
// return this[PROPERTIES].requiredError;
|
|
578
|
-
// }
|
|
579
|
-
// set requiredError(value) {
|
|
580
|
-
// this[PROPERTIES].requiredError = '' + value;
|
|
581
|
-
// }
|
|
582
|
-
// /**
|
|
583
|
-
// * 标签
|
|
584
|
-
// *
|
|
585
|
-
// * @example
|
|
586
|
-
// * // 可通过 slot 定制
|
|
587
|
-
// * <form-item>
|
|
588
|
-
// * <span slot="label">定制 Label 内容</span>
|
|
589
|
-
// * </form-item>
|
|
590
|
-
// */
|
|
591
|
-
// get label(): string {
|
|
592
|
-
// return this.slots.label.textContent;
|
|
593
|
-
// }
|
|
594
|
-
// set label(value) {
|
|
595
|
-
// this.slots.label.textContent = value;
|
|
596
|
-
// }
|
|
597
|
-
// /**
|
|
598
|
-
// * 标签宽度(未设置则继承所属表单的标签宽度)
|
|
599
|
-
// */
|
|
600
|
-
// get labelWidth(): string {
|
|
601
|
-
// return this[PROPERTIES].labelWidth;
|
|
602
|
-
// }
|
|
603
|
-
// set labelWidth(value) {
|
|
604
|
-
// let properties = this[PROPERTIES];
|
|
605
|
-
// let label;
|
|
606
|
-
// if (properties.labelWidth !== (value = '' + value)) {
|
|
607
|
-
// label = this.slots.label;
|
|
608
|
-
// label.style.width = properties.labelWidth = value;
|
|
609
|
-
// if (value[0] !== '0') {
|
|
610
|
-
// label.removeAttribute('hidden');
|
|
611
|
-
// } else {
|
|
612
|
-
// label.setAttribute('hidden', '');
|
|
613
|
-
// }
|
|
614
|
-
// }
|
|
615
|
-
// }
|
|
616
|
-
// /**
|
|
617
|
-
// * 标签对齐方式(未设置则继承所属表单的对齐方式)
|
|
618
|
-
// */
|
|
619
|
-
// get align(): '' | 'left' | 'right' | 'top' {
|
|
620
|
-
// return (this.getAttribute('align') as '') || '';
|
|
621
|
-
// }
|
|
622
|
-
// set align(value) {
|
|
623
|
-
// this.setAttribute('align', value);
|
|
624
|
-
// }
|
|
625
|
-
// /**
|
|
626
|
-
// * 错误信息
|
|
627
|
-
// */
|
|
628
|
-
// get error(): string {
|
|
629
|
-
// return this[PROPERTIES].error;
|
|
630
|
-
// }
|
|
631
|
-
// set error(value) {
|
|
632
|
-
// let properties = this[PROPERTIES];
|
|
633
|
-
// let error = properties.error;
|
|
634
|
-
// let dom = error && findComponent(this, 'jw-form-error');
|
|
635
|
-
// if ((properties.error = value)) {
|
|
636
|
-
// if (dom) {
|
|
637
|
-
// dom.textContent = value;
|
|
638
|
-
// } else {
|
|
639
|
-
// dom = createComponent('div');
|
|
640
|
-
// dom.className = 'jw-form-error';
|
|
641
|
-
// dom.textContent = value;
|
|
642
|
-
// this.slots.default.appendChild(dom);
|
|
643
|
-
// }
|
|
644
|
-
// } else if (dom) {
|
|
645
|
-
// dom.parentNode.removeChild(dom);
|
|
646
|
-
// }
|
|
647
|
-
// }
|
|
648
|
-
// /**
|
|
649
|
-
// * 点击 Label 自动获取焦点的组件(选择器)
|
|
650
|
-
// */
|
|
651
|
-
// get for(): string {
|
|
652
|
-
// return this[PROPERTIES].for;
|
|
653
|
-
// }
|
|
654
|
-
// set for(value) {
|
|
655
|
-
// this[PROPERTIES].for = '' + value;
|
|
656
|
-
// }
|
|
657
|
-
// /**
|
|
658
|
-
// * 是否隐藏
|
|
659
|
-
// */
|
|
660
|
-
// get hidden(): boolean {
|
|
661
|
-
// return this.style.display === 'none';
|
|
662
|
-
// }
|
|
663
|
-
// set hidden(value) {
|
|
664
|
-
// this.style.display = value ? 'none' : '';
|
|
665
|
-
// }
|
|
666
|
-
// /**
|
|
667
|
-
// * 元素被插入到文档时触发
|
|
668
|
-
// */
|
|
669
|
-
// connectedCallback() {
|
|
670
|
-
// let properties = this[PROPERTIES];
|
|
671
|
-
// let slots = this.slots;
|
|
672
|
-
// let label = slots.label;
|
|
673
|
-
// // 第一次初始化
|
|
674
|
-
// if (!label.parentNode) {
|
|
675
|
-
// this.initTemplate(label, slots.default);
|
|
676
|
-
// BROWSER &&
|
|
677
|
-
// label.addEventListener('click', () => {
|
|
678
|
-
// let input = (this as unknown as HTMLElement).querySelector(
|
|
679
|
-
// this.for || 'input,textarea,select',
|
|
680
|
-
// ) as HTMLElement;
|
|
681
|
-
// if (input) {
|
|
682
|
-
// input.focus();
|
|
683
|
-
// }
|
|
684
|
-
// });
|
|
685
|
-
// }
|
|
686
|
-
// // 没有设置标签宽度
|
|
687
|
-
// if (!properties.labelWidth) {
|
|
688
|
-
// let parent = this.parentNode;
|
|
689
|
-
// while (parent) {
|
|
690
|
-
// if (parent instanceof Form) {
|
|
691
|
-
// if (parent.labelWidth) {
|
|
692
|
-
// label.style.width = parent.labelWidth;
|
|
693
|
-
// label.removeAttribute('hidden');
|
|
694
|
-
// }
|
|
695
|
-
// break;
|
|
696
|
-
// }
|
|
697
|
-
// parent = parent.parentNode;
|
|
698
|
-
// }
|
|
699
|
-
// }
|
|
700
|
-
// }
|
|
701
|
-
|
|
702
463
|
const form = useContext(FormContext) as any;
|
|
703
464
|
|
|
465
|
+
let item: HTMLElement;
|
|
466
|
+
|
|
467
|
+
onMount(() => {
|
|
468
|
+
(item as any).FORM_ITEM = props;
|
|
469
|
+
});
|
|
470
|
+
|
|
704
471
|
return (
|
|
705
472
|
<div
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
473
|
+
ref={item as any}
|
|
474
|
+
class={combineClass(
|
|
475
|
+
'form-item',
|
|
476
|
+
'form-align-' + (thisProps.align || form.align || 'left'),
|
|
477
|
+
thisProps.required && 'required',
|
|
478
|
+
thisProps.hidden && 'hidden',
|
|
479
|
+
thisProps.class,
|
|
480
|
+
)}
|
|
709
481
|
{...restProps}
|
|
710
482
|
>
|
|
711
|
-
<label for={thisProps.for} style={{ width: thisProps.labelWidth || form.
|
|
483
|
+
<label for={thisProps.for} style={{ width: thisProps.labelWidth || form.labelWidth }}>
|
|
712
484
|
{thisProps.label}
|
|
713
485
|
</label>
|
|
714
486
|
<div class="form-body">{thisProps.children}</div>
|
|
@@ -716,18 +488,6 @@ export const FormItem = (props?: JSX.HTMLAttributes<never> & FormItemProps) => {
|
|
|
716
488
|
);
|
|
717
489
|
};
|
|
718
490
|
|
|
719
|
-
function validateForm(
|
|
720
|
-
form: HTMLFormElement,
|
|
721
|
-
items: HTMLElement[],
|
|
722
|
-
rules: ValidateRules,
|
|
723
|
-
data: object,
|
|
724
|
-
filter?: (target: ValidateTarget) => void | boolean,
|
|
725
|
-
) {
|
|
726
|
-
// return rules ? validate(this, this, rules, this.data || {}, filter) : 0;
|
|
727
|
-
|
|
728
|
-
return Promise.resolve(true);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
491
|
function scrollToError(this: HTMLFormElement) {
|
|
732
492
|
let error = this.querySelector('.form-error') as HTMLElement;
|
|
733
493
|
|
|
@@ -784,7 +544,7 @@ export const Form = (
|
|
|
784
544
|
/**
|
|
785
545
|
* label 对齐方式
|
|
786
546
|
*/
|
|
787
|
-
align?: 'left' | '
|
|
547
|
+
align?: 'left' | 'top' | 'right';
|
|
788
548
|
|
|
789
549
|
/**
|
|
790
550
|
* 标签宽度
|
|
@@ -801,59 +561,22 @@ export const Form = (
|
|
|
801
561
|
|
|
802
562
|
let form: HTMLFormElement;
|
|
803
563
|
|
|
804
|
-
// /**
|
|
805
|
-
// * label 对齐方式
|
|
806
|
-
// */
|
|
807
|
-
// get align(): 'left' | 'right' | 'top' {
|
|
808
|
-
// return this.getAttribute('align') as 'left' || 'left';
|
|
809
|
-
// }
|
|
810
|
-
// set align(value) {
|
|
811
|
-
// this.setAttribute('align', value);
|
|
812
|
-
// }
|
|
813
|
-
// /**
|
|
814
|
-
// * 标签宽度
|
|
815
|
-
// */
|
|
816
|
-
// get labelWidth(): string {
|
|
817
|
-
// return this[PROPERTIES].labelWidth;
|
|
818
|
-
// }
|
|
819
|
-
// set labelWidth(value) {
|
|
820
|
-
// let properties = this[PROPERTIES];
|
|
821
|
-
// value = value ? '' + value : '';
|
|
822
|
-
// if (properties.labelWidth !== value) {
|
|
823
|
-
// properties.labelWidth = value;
|
|
824
|
-
// if (this.firstChild) {
|
|
825
|
-
// update(this, value);
|
|
826
|
-
// }
|
|
827
|
-
// }
|
|
828
|
-
// }
|
|
829
|
-
|
|
830
564
|
onMount(() => {
|
|
831
565
|
// 初始化外部调用接口
|
|
832
566
|
props.api &&
|
|
833
|
-
props.api(
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
567
|
+
props.api(
|
|
568
|
+
(form.api = {
|
|
569
|
+
validate: (filter?: (target: ValidateTarget) => void | boolean) =>
|
|
570
|
+
validate(form, thisProps.rules, thisProps.data, filter),
|
|
571
|
+
scrollToError: scrollToError.bind(form),
|
|
572
|
+
clearErrors: clearErrors.bind(form),
|
|
573
|
+
}),
|
|
574
|
+
);
|
|
839
575
|
});
|
|
840
576
|
|
|
841
|
-
const items = () => {
|
|
842
|
-
let items = children(() => {
|
|
843
|
-
return thisProps.children;
|
|
844
|
-
})();
|
|
845
|
-
|
|
846
|
-
return items;
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
// const context = createMemo(() => ({
|
|
850
|
-
// align: thisProps.align,
|
|
851
|
-
// width: thisProps.labelWidth,
|
|
852
|
-
// }));
|
|
853
|
-
|
|
854
577
|
return (
|
|
855
578
|
<form ref={form as any} {...restProps}>
|
|
856
|
-
<FormContext.Provider value={thisProps}>{
|
|
579
|
+
<FormContext.Provider value={thisProps}>{thisProps.children}</FormContext.Provider>
|
|
857
580
|
</form>
|
|
858
581
|
);
|
|
859
582
|
};
|