@fairys/valtio-form-basic 0.0.8 → 0.0.10

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.
@@ -1,14 +1,27 @@
1
1
  /**表单项*/
2
2
 
3
3
  import { MObject } from 'interface';
4
- import React, { useMemo } from 'react';
4
+ import React, { useEffect, useMemo } from 'react';
5
5
  import clsx from 'clsx';
6
6
  import { useFairysValtioFormInstanceContextState, FairysValtioFormInstance } from './instance';
7
7
  import { useFairysValtioFormLayoutContext, FairysValtioFormLayoutContextOptions } from './layout';
8
+ import { FairysValtioFormParentAttrs, useFairysValtioFormAttrsName } from './hooks';
9
+ import { get } from './utils';
10
+ import { RuleItem } from 'async-validator';
8
11
 
9
12
  export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
10
- /**表单项名称*/
11
- name: string;
13
+ /**
14
+ * 表单项名称 ,字段需要和存储的字段路径一致
15
+ *
16
+ * @example
17
+ * 路径中的值为 number 类型时,会创建一个空数组。路径中的值为 string 类型时,会创建一个空对象。最后一个直接赋值
18
+ *
19
+ * 默认:"name"
20
+ * 嵌套字段:"name.a.doc" ===> { name: { a: { doc: undefined } } }
21
+ * 嵌套字段:"name[1].a.doc" ===> { name: [{}, { a: { doc: undefined } }] }
22
+ * 嵌套字段:"name.a[2].doc" ===> { name: { a: [{}, {}, { doc: undefined }] } }
23
+ */
24
+ name?: string;
12
25
  /**表单项标签*/
13
26
  label?: string;
14
27
  /**传递组件字段*/
@@ -29,9 +42,9 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
29
42
  bodyStyle?: React.CSSProperties;
30
43
  children?: React.ReactNode;
31
44
  /**规则校验失败错误提示位置*/
32
- errorLayout?: 'left-bottom' | 'right-bottom' | 'top-right' | 'top-left';
45
+ errorLayout?: FairysValtioFormLayoutContextOptions['errorLayout'];
33
46
  /**label显示模式*/
34
- labelMode?: 'left' | 'top' | 'between';
47
+ labelMode?: FairysValtioFormLayoutContextOptions['labelMode'];
35
48
  /**额外内容*/
36
49
  extra?: React.ReactNode;
37
50
  /**底部提示内容*/
@@ -51,9 +64,19 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
51
64
  /**是否显示冒号*/
52
65
  showColon?: boolean;
53
66
  /**底部显示边框*/
54
- borderedType?: FairysValtioFormLayoutContextOptions['borderedType'];
67
+ itemBorderType?: FairysValtioFormLayoutContextOptions['itemBorderType'];
68
+ /**边框颜色*/
69
+ itemBorderColor?: React.CSSProperties['borderColor'];
70
+ /**是否校验失败时显示红色边框*/
71
+ isInvalidBorderRed?: boolean;
72
+ /**是否校验失败时显示红色文本*/
73
+ isInvalidTextRed?: boolean;
55
74
  /**输入框属性*/
56
75
  attrs?: any;
76
+ /**是否拼接父级字段名*/
77
+ isJoinParentField?: boolean;
78
+ /**校验规则*/
79
+ rules?: RuleItem[];
57
80
  }
58
81
 
59
82
  /**
@@ -63,7 +86,7 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
63
86
  *
64
87
  * ```tsx
65
88
  import { Fragment } from 'react'
66
- import { useFairysValtioFormItemAttrs } from "@fairys/valtio-form"
89
+ import { useFairysValtioFormItemAttrs , FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
67
90
  import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
68
91
  export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
69
92
 
@@ -72,10 +95,11 @@ export const FormItem = (props: FormItemProps) => {
72
95
  const {
73
96
  itemClassName, itemStyle, containerClassName, itemLabelClassName, itemLabelStyle,
74
97
  itemBodyClassName, itemBodyStyle, itemInputClassName, itemExtraClassName, errorClassName, helpClassName,
75
- isInvalid, borderedType, children, error
98
+ isInvalid, itemBorderType, children, error,formAttrsNameInstance
76
99
  } = useFairysValtioFormItemAttrs(props)
77
100
 
78
101
  return (
102
+ <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
79
103
  <View className={itemClassName} style={itemStyle}>
80
104
  <View className={containerClassName}>
81
105
  <View className={itemLabelClassName} style={itemLabelStyle}>
@@ -86,12 +110,13 @@ export const FormItem = (props: FormItemProps) => {
86
110
  {children}
87
111
  </View>
88
112
  {extra ? <View className={itemExtraClassName}>{extra}</View> : <Fragment />}
89
- {borderedType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
113
+ {itemBorderType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
90
114
  </View>
91
115
  </View>
92
116
  {helpText ? <View className={helpClassName}>{helpText}</View> : <Fragment />}
93
- {isInvalid && borderedType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
117
+ {isInvalid && itemBorderType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
94
118
  </View>
119
+ </FairysValtioFormParentAttrsContext.Provider>
95
120
  );
96
121
  }
97
122
  * ```
@@ -100,8 +125,8 @@ export const FormItem = (props: FormItemProps) => {
100
125
  export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(props: FairysValtioFormItemAttrsProps<T>) {
101
126
  const [layoutAttrs] = useFairysValtioFormLayoutContext();
102
127
  const colCount = layoutAttrs.colCount || 1;
103
- const parent_borderedType = layoutAttrs.borderedType || 'bottom';
104
- const parent_errorLayout = layoutAttrs.errorLayout || 'right-bottom';
128
+ const parent_borderedType = layoutAttrs.itemBorderType || 'bottom';
129
+ const parent_errorLayout = layoutAttrs.errorLayout || 'bottom-right';
105
130
  const parent_formItemClassName = layoutAttrs.formItemClassName;
106
131
  const parent_formItemLabelClassName = layoutAttrs.formItemLabelClassName;
107
132
  const parent_formItemLabelStyle = layoutAttrs.formItemLabelStyle;
@@ -109,6 +134,11 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
109
134
  const parent_formItemBodyClassName = layoutAttrs.formItemBodyClassName;
110
135
  const parent_formItemBodyStyle = layoutAttrs.formItemBodyStyle;
111
136
  const parent_labelMode = layoutAttrs.labelMode || 'between';
137
+ const parent_itemBorderColor = layoutAttrs.itemBorderColor;
138
+ const parent_isInvalidBorderRed = layoutAttrs.isInvalidBorderRed;
139
+ const parent_isInvalidTextRed = layoutAttrs.isInvalidTextRed;
140
+ const parent_showColon = layoutAttrs.showColon;
141
+
112
142
  const {
113
143
  name,
114
144
  valuePropName = 'value',
@@ -128,14 +158,38 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
128
158
  colSpan = 1,
129
159
  rowSpan = 1,
130
160
  isRequired: _isRequired,
131
- borderedType = parent_borderedType,
161
+ itemBorderType = parent_borderedType,
132
162
  attrs = {},
133
- showColon = false,
163
+ showColon = parent_showColon,
164
+ itemBorderColor = parent_itemBorderColor,
165
+ isInvalidBorderRed = parent_isInvalidBorderRed,
166
+ isInvalidTextRed = parent_isInvalidTextRed,
167
+ isJoinParentField = true,
168
+ rules,
134
169
  } = props;
170
+
171
+ const {
172
+ name: _name,
173
+ paths,
174
+ parentName,
175
+ formAttrsNameInstance,
176
+ } = useFairysValtioFormAttrsName({ name, isJoinParentField });
135
177
  const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
136
- const rules = formInstance.rules?.[name];
137
- const value = state[name];
138
- const error = errorState[name];
178
+ const value = useMemo(() => get(state, paths), [state, paths]);
179
+ const error = errorState[_name];
180
+ // 使用从 Form 中设置的规则
181
+ const _formItemRules = formInstance.rules?.[_name];
182
+
183
+ formInstance.nameToPaths[_name] = paths;
184
+ /**挂载校验规则*/
185
+ if (Array.isArray(rules) && rules.length) {
186
+ formInstance.mountRules[_name] = rules;
187
+ }
188
+ useEffect(() => {
189
+ return () => {
190
+ formInstance.removeRules(_name);
191
+ };
192
+ }, [_name]);
139
193
 
140
194
  const onValueChange = (event: any) => {
141
195
  let value = event;
@@ -148,7 +202,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
148
202
  if (typeof formatValue === 'function') {
149
203
  value = formatValue(value, formInstance, event);
150
204
  }
151
- formInstance.updated({ [name]: value });
205
+ formInstance.updatedValueByPaths(_name, value);
152
206
  if (typeof onAfterUpdate === 'function') {
153
207
  onAfterUpdate(value, formInstance, event);
154
208
  }
@@ -168,9 +222,11 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
168
222
  return _isRequired;
169
223
  } else if (Array.isArray(rules) && rules.length) {
170
224
  return rules.some((rule) => rule.required);
225
+ } else if (_formItemRules && Array.isArray(_formItemRules) && _formItemRules.length) {
226
+ return _formItemRules.some((rule) => rule.required);
171
227
  }
172
228
  return false;
173
- }, [rules, formInstance]);
229
+ }, [rules, formInstance, _formItemRules]);
174
230
 
175
231
  /**校验是否存在错误信息*/
176
232
  const isInvalid = useMemo(() => {
@@ -183,22 +239,25 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
183
239
  /**表单项类名*/
184
240
  const item_cls = useMemo(() => {
185
241
  return clsx(
186
- 'fairys-valtio-form-item fairystaroform__p-[4px] fairystaroform__text-[12px] fairystaroform__relative fairystaroform__flex fairystaroform__flex-col fairystaroform__box-border fairystaroform__break-all',
242
+ 'fairys-valtio-form-item fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__p-[4px] fairystaroform__text-[12px] fairystaroform__relative fairystaroform__flex fairystaroform__flex-col fairystaroform__box-border fairystaroform__break-all',
187
243
  {
244
+ 'fairys-valtio-form-item-invalid': isInvalid,
245
+ 'fairys-valtio-form-item-invalid-text-red': isInvalid && isInvalidTextRed,
246
+ 'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && itemBorderType === 'bottom',
188
247
  'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200':
189
- borderedType === 'bottom',
248
+ itemBorderType === 'bottom',
190
249
  [labelMode]: labelMode,
191
250
  },
192
- className,
193
251
  parent_formItemClassName,
252
+ className,
194
253
  );
195
- }, [className, parent_formItemClassName, labelMode, borderedType]);
254
+ }, [className, parent_formItemClassName, labelMode, itemBorderType, isInvalid, isInvalidBorderRed]);
196
255
 
197
256
  /**表单项容器类名*/
198
257
  const itemContainer_cls = useMemo(() => {
199
258
  // 默认两端显示
200
259
  return clsx(
201
- 'fairys-valtio-form-item-container fairystaroform__flex-1 fairystaroform__h-full fairystaroform__flex fairystaroform__box-border',
260
+ 'fairys-valtio-form-item-container fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__flex-1 fairystaroform__h-full fairystaroform__flex fairystaroform__box-border',
202
261
  {
203
262
  'fairystaroform__flex-row fairystaroform__items-center fairystaroform__justify-between fairystaroform__gap-[8px]':
204
263
  labelMode === 'between',
@@ -213,7 +272,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
213
272
  const itemLabel_cls = useMemo(() => {
214
273
  // 默认两端显示
215
274
  return clsx(
216
- 'fairys-valtio-form-item-label fairystaroform__text-gray-800 fairystaroform__flex fairystaroform__items-center fairystaroform__relative fairystaroform__box-border',
275
+ 'fairys-valtio-form-item-label fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__text-gray-800 fairystaroform__flex fairystaroform__items-center fairystaroform__relative fairystaroform__box-border',
217
276
  {
218
277
  'fairystaroform__justify-start': labelMode !== 'left',
219
278
  'fairystaroform__justify-end': labelMode === 'left',
@@ -229,23 +288,24 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
229
288
  const itemBody_cls = useMemo(() => {
230
289
  // 默认两端显示
231
290
  return clsx(
232
- 'fairys-valtio-form-item-body fairystaroform__relative fairystaroform__flex-1 fairystaroform__flex fairystaroform__box-border',
291
+ 'fairys-valtio-form-item-body fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__relative fairystaroform__flex-1 fairystaroform__flex fairystaroform__box-border',
233
292
  {
234
293
  'fairystaroform__flex-row fairystaroform__justify-start': labelMode === 'left',
235
294
  'fairystaroform__flex-row fairystaroform__justify-end': labelMode === 'between' || labelMode === 'top',
236
295
  'fairystaroform__flex-row': labelMode === 'top',
237
296
  'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200 ':
238
- borderedType === 'body',
297
+ itemBorderType === 'body',
298
+ 'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && itemBorderType === 'body',
239
299
  },
240
- bodyClassName,
241
300
  parent_formItemBodyClassName,
301
+ bodyClassName,
242
302
  );
243
- }, [bodyClassName, labelMode, borderedType, parent_formItemBodyClassName]);
303
+ }, [bodyClassName, labelMode, itemBorderType, parent_formItemBodyClassName, isInvalid, isInvalidBorderRed]);
244
304
 
245
305
  // 表单项输入类名
246
306
  const itemInput_cls = useMemo(() => {
247
307
  return clsx(
248
- 'fairys-valtio-form-item-body fairystaroform__flex fairystaroform__flex-row fairystaroform__flex-1 fairystaroform__box-border',
308
+ 'fairys-valtio-form-item-body-input fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__min-h-[32px] fairystaroform__flex fairystaroform__flex-row fairystaroform__items-center fairystaroform__flex-1 fairystaroform__box-border',
249
309
  {
250
310
  'fairystaroform__justify-end fairystaroform__text-right': labelMode === 'between',
251
311
  'fairystaroform__justify-start fairystaroform__text-left fairystaroform__items-center': labelMode !== 'between',
@@ -256,28 +316,34 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
256
316
  /**表单项额外内容类名*/
257
317
  const itemExtra_cls = useMemo(() => {
258
318
  return clsx(
259
- 'fairys-valtio-form-item-body-extra fairystaroform__box-border fairystaroform__flex fairystaroform__items-center fairystaroform__justify-center',
319
+ 'fairys-valtio-form-item-body-extra fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__box-border fairystaroform__flex fairystaroform__items-center fairystaroform__justify-center',
260
320
  );
261
321
  }, []);
262
322
 
263
323
  /**表单项底部提示内容类名*/
264
324
  const itemHelp_cls = useMemo(() => {
265
325
  return clsx(
266
- 'fairys-valtio-form-item-body-help fairystaroform__text-[10px] fairystaroform__w-full fairystaroform__box-border',
326
+ 'fairys-valtio-form-item-body-help fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__text-[10px] fairystaroform__w-full fairystaroform__box-border',
267
327
  );
268
328
  }, []);
269
329
 
270
330
  /**表单项错误提示类名*/
271
331
  const itemError_cls = useMemo(() => {
272
332
  return clsx(
273
- 'fairys-valtio-form-item-body-error fairystaroform__px-[4px] fairystaroform__w-full fairystaroform__flex fairystaroform__flex-row fairystaroform__box-border fairystaroform__text-red fairystaroform__absolute fairystaroform__text-[10px] fairystaroform__z-10',
333
+ 'fairys-valtio-form-item-body-error fairystaroform__transition-all fairystaroform__duration-300 fairystaroform__w-full fairystaroform__flex fairystaroform__flex-row fairystaroform__box-border fairystaroform__text-red fairystaroform__absolute fairystaroform__text-[10px] fairystaroform__z-10',
274
334
  {
275
335
  'fairystaroform__bottom-[-14px] fairystaroform__left-0 fairystaroform__justify-start':
276
- errorLayout === 'left-bottom',
336
+ errorLayout === 'bottom-left',
277
337
  'fairystaroform__bottom-[-14px] fairystaroform__right-0 fairystaroform__justify-end':
278
- errorLayout === 'right-bottom',
279
- 'fairystaroform__top-[-14px] fairystaroform__right-0 fairystaroform__justify-end': errorLayout === 'top-right',
280
- 'fairystaroform__top-[-14px] fairystaroform__left-0 fairystaroform__justify-start': errorLayout === 'top-left',
338
+ errorLayout === 'bottom-right',
339
+ 'fairystaroform__top-[-4px] fairystaroform__right-0 fairystaroform__justify-end': errorLayout === 'top-right',
340
+ 'fairystaroform__top-[-4px] fairystaroform__left-0 fairystaroform__justify-start': errorLayout === 'top-left',
341
+ /**边框底部提示*/
342
+ 'fairystaroform__left-0 fairystaroform__bottom-[-2px] fairystaroform__justify-start':
343
+ errorLayout === 'left-border-top',
344
+ /**边框顶部提示*/
345
+ 'fairystaroform__right-0 fairystaroform__bottom-[-2px] fairystaroform__justify-end':
346
+ errorLayout === 'right-border-top',
281
347
  },
282
348
  );
283
349
  }, [errorLayout]);
@@ -297,7 +363,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
297
363
  return {
298
364
  value,
299
365
  isInvalid,
300
- borderedType,
366
+ itemBorderType,
301
367
  onValueChange,
302
368
  colSpan,
303
369
  rowSpan,
@@ -309,14 +375,28 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
309
375
  errorState,
310
376
  formInstance,
311
377
  error,
378
+ _name,
379
+ name,
380
+ paths,
381
+ parentName,
382
+ formAttrsNameInstance,
312
383
  // ================================================================================
313
384
  itemClassName: item_cls,
314
- itemStyle: { ...(parent_formItemStyle || {}), ...styleBase, ...(style || {}) },
385
+ itemStyle: {
386
+ ...(itemBorderColor && itemBorderType === 'bottom' ? { borderBottomColor: itemBorderColor } : {}),
387
+ ...(parent_formItemStyle || {}),
388
+ ...styleBase,
389
+ ...(style || {}),
390
+ },
315
391
  containerClassName: itemContainer_cls,
316
392
  itemLabelClassName: itemLabel_cls,
317
393
  itemLabelStyle: { ...(parent_formItemLabelStyle || {}), ...(labelStyle || {}) },
318
394
  itemBodyClassName: itemBody_cls,
319
- itemBodyStyle: { ...(parent_formItemBodyStyle || {}), ...(bodyStyle || {}) },
395
+ itemBodyStyle: {
396
+ ...(itemBorderColor && itemBorderType === 'body' ? { borderBottomColor: itemBorderColor } : {}),
397
+ ...(parent_formItemBodyStyle || {}),
398
+ ...(bodyStyle || {}),
399
+ },
320
400
  itemInputClassName: itemInput_cls,
321
401
  itemExtraClassName: itemExtra_cls,
322
402
  errorClassName: itemError_cls,
@@ -329,31 +409,41 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
329
409
  /**表单项值*/
330
410
  value?: any;
331
411
  /**是否校验错误*/
332
- isInvalid?: boolean;
412
+ isInvalid: boolean;
333
413
  /**边框类型*/
334
- borderedType?: FairysValtioFormLayoutContextOptions['borderedType'];
414
+ itemBorderType: FairysValtioFormLayoutContextOptions['itemBorderType'];
335
415
  /**值改变事件*/
336
- onValueChange?: (event: any) => void;
416
+ onValueChange: (event: any) => void;
337
417
  /**当前表单项占据列数*/
338
- colSpan?: number;
418
+ colSpan: number;
339
419
  /**当前表单项占据行数*/
340
- rowSpan?: number;
420
+ rowSpan: number;
341
421
  /**列数*/
342
- colCount?: number;
422
+ colCount: number;
343
423
  /**标签显示模式*/
344
- labelMode?: FairysValtioFormLayoutContextOptions['labelMode'];
424
+ labelMode: FairysValtioFormLayoutContextOptions['labelMode'];
345
425
  /**错误提示位置*/
346
- errorLayout?: FairysValtioFormLayoutContextOptions['errorLayout'];
426
+ errorLayout: FairysValtioFormLayoutContextOptions['errorLayout'];
347
427
  /**是否必填*/
348
- isRequired?: boolean;
428
+ isRequired: boolean;
349
429
  /**表单状态*/
350
- state?: T;
430
+ state: T;
351
431
  /**错误状态*/
352
- errorState?: Record<PropertyKey, string[]>;
432
+ errorState: Record<PropertyKey, string[]>;
353
433
  /**表单实例*/
354
- formInstance?: FairysValtioFormInstance<T>;
434
+ formInstance: FairysValtioFormInstance<T>;
355
435
  /**错误信息*/
356
436
  error?: string[];
437
+ /**拼接父级字段名后得到的表单项名称*/
438
+ _name?: string;
439
+ /**表单项名称*/
440
+ name?: string;
441
+ /**表单项路径*/
442
+ paths?: (string | number)[];
443
+ /**父级字段名*/
444
+ parentName?: string;
445
+ /**表单属性名实例*/
446
+ formAttrsNameInstance: FairysValtioFormParentAttrs;
357
447
  // =========================================
358
448
  /**表单项类名*/
359
449
  itemClassName: string;
@@ -380,3 +470,97 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
380
470
  /**子元素*/
381
471
  children?: React.ReactNode;
382
472
  }
473
+
474
+ /**
475
+ * 没有样式的表单项属性,仅返回基础输入组件参数
476
+ *
477
+ * @example
478
+ *
479
+ *```tsx
480
+ import { Fragment } from 'react'
481
+ import { useFairysValtioFormItemAttrs, FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
482
+ import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
483
+ export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
484
+
485
+ export const FormItem = (props: FormItemProps) => {
486
+ const { children , formAttrsNameInstance } = useFairysValtioFormItemNoStyleAttrs(props)
487
+ return <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
488
+ {children}
489
+ </FairysValtioFormParentAttrsContext.Provider>
490
+ }
491
+ * ```
492
+ */
493
+ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = object>(
494
+ props: FairysValtioFormItemAttrsProps<T>,
495
+ ) {
496
+ const {
497
+ name,
498
+ valuePropName = 'value',
499
+ getValueFromEvent,
500
+ formatValue,
501
+ onAfterUpdate,
502
+ trigger = 'onChange',
503
+ children,
504
+ attrs = {},
505
+ isJoinParentField = true,
506
+ rules,
507
+ } = props;
508
+ const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
509
+ const {
510
+ name: _name,
511
+ paths,
512
+ parentName,
513
+ formAttrsNameInstance,
514
+ } = useFairysValtioFormAttrsName({ name, isJoinParentField });
515
+ const value = useMemo(() => get(state, paths), [state, paths]);
516
+ const error = errorState[_name];
517
+ formInstance.nameToPaths[_name] = paths;
518
+ /**挂载校验规则*/
519
+ if (Array.isArray(rules) && rules.length) {
520
+ formInstance.mountRules[_name] = rules;
521
+ }
522
+
523
+ useEffect(() => {
524
+ return () => {
525
+ formInstance.removeRules(_name);
526
+ };
527
+ }, [_name]);
528
+
529
+ const onValueChange = (event: any) => {
530
+ let value = event;
531
+ const target = event?.detail || event?.target;
532
+ if (typeof getValueFromEvent === 'function') {
533
+ value = getValueFromEvent(event, formInstance);
534
+ } else if (event && target && typeof target === 'object' && valuePropName in target) {
535
+ value = target.valuePropName;
536
+ }
537
+ if (typeof formatValue === 'function') {
538
+ value = formatValue(value, formInstance, event);
539
+ }
540
+ formInstance.updatedValueByPaths(_name, value);
541
+ if (typeof onAfterUpdate === 'function') {
542
+ onAfterUpdate(value, formInstance, event);
543
+ }
544
+ };
545
+ /**基础组件参数*/
546
+ const baseControl = {
547
+ ...attrs,
548
+ name,
549
+ [valuePropName]: value,
550
+ [trigger]: onValueChange,
551
+ };
552
+ return {
553
+ value,
554
+ error,
555
+ onValueChange,
556
+ state,
557
+ errorState,
558
+ formInstance,
559
+ _name,
560
+ name,
561
+ paths,
562
+ parentName,
563
+ formAttrsNameInstance,
564
+ children: React.isValidElement(children) ? React.cloneElement(children, { ...baseControl }) : children,
565
+ };
566
+ }
package/src/form/form.tsx CHANGED
@@ -2,14 +2,15 @@ import { MObject } from 'interface';
2
2
  import { FairysValtioFormInstance, useFairysValtioFormInstance } from './instance';
3
3
  import { useMemo, type ReactNode } from 'react';
4
4
  import { FairysValtioFormLayoutAttrsProps } from './layout';
5
+ import { RuleItem } from 'async-validator';
5
6
 
6
7
  export interface FairysValtioFormAttrsProps<T extends MObject<T> = object> extends FairysValtioFormLayoutAttrsProps {
7
8
  /**表单实例*/
8
9
  form?: FairysValtioFormInstance<T>;
9
10
  /**子元素*/
10
11
  children: ReactNode;
11
- /**表单项规则*/
12
- rules?: FairysValtioFormInstance<T>['rules'];
12
+ /**表单项规则(如果表单项没有指定规则,则使用全局规则,如果表单项指定规则,则使用表单项规则)*/
13
+ rules?: Record<PropertyKey, RuleItem[]>;
13
14
  /**表单初始值*/
14
15
  formData?: FairysValtioFormInstance<T>['state'];
15
16
  /**表单隐藏状态*/
@@ -49,20 +50,4 @@ export function useFairysValtioForm<T extends MObject<T> = object>(props: Fairys
49
50
  ...rest,
50
51
  formInstance,
51
52
  };
52
- // return (
53
- // <FairysValtioFormInstanceContext.Provider value={formInstance}>
54
- // <FairysValtioFormLayout {...rest}>{children}</FairysValtioFormLayout>
55
- // </FairysValtioFormInstanceContext.Provider>
56
- // );
57
53
  }
58
-
59
- // /**初始化实例*/
60
- // FairysValtioForm.useForm = useFairysValtioFormInstance;
61
- // /**获取状态*/
62
- // FairysValtioForm.useFormState = useFairysValtioFormInstanceContextState;
63
- // /**获取隐藏状态*/
64
- // FairysValtioForm.useFormHideState = useFairysValtioFormInstanceContextHideState;
65
- // /**获取上下文实例*/
66
- // FairysValtioForm.useFormInstance = useFairysValtioFormInstanceContext;
67
- // /**表单项*/
68
- // FairysValtioForm.useFormItemAttrs = useFairysValtioFormItemAttrs;
@@ -0,0 +1,78 @@
1
+ import { useRef, createContext, useContext, useMemo } from 'react';
2
+ import { proxy, useSnapshot } from 'valtio';
3
+ import { formatePath, formateName } from 'form/utils';
4
+ export interface FairysValtioFormParentAttrsState {
5
+ name?: string;
6
+ }
7
+
8
+ /***
9
+ * 父级属性
10
+ */
11
+ export class FairysValtioFormParentAttrs {
12
+ state = proxy<FairysValtioFormParentAttrsState>({
13
+ name: '',
14
+ });
15
+ // ===================================================更新状态================================================================
16
+ updated = (attrs: Record<string, any>) => {
17
+ this.state = { ...this.state, ...attrs };
18
+ };
19
+ /***更新父级字段值*/
20
+ updatedName = (name?: string, parentName?: string) => {
21
+ this.state.name = formateName(name, parentName);
22
+ };
23
+ }
24
+
25
+ /**初始化父级属性*/
26
+ export const useFairysValtioFormParentAttrs = (instance?: FairysValtioFormParentAttrs) => {
27
+ const parentAttrs = useRef<FairysValtioFormParentAttrs>();
28
+ if (!parentAttrs.current) {
29
+ if (instance) {
30
+ parentAttrs.current = instance;
31
+ } else {
32
+ parentAttrs.current = new FairysValtioFormParentAttrs();
33
+ }
34
+ }
35
+ return parentAttrs.current;
36
+ };
37
+
38
+ /***父级属性上下文*/
39
+ export const FairysValtioFormParentAttrsContext = createContext<FairysValtioFormParentAttrs>(
40
+ new FairysValtioFormParentAttrs(),
41
+ );
42
+
43
+ /***获取父级属性实例*/
44
+ export const useFairysValtioFormParentAttrsContext = () => useContext(FairysValtioFormParentAttrsContext);
45
+
46
+ /***获取父级属性状态*/
47
+ export const useFairysValtioFormParentAttrsState = () => {
48
+ const instance = useFairysValtioFormParentAttrsContext();
49
+ const state = useSnapshot(instance.state);
50
+ return [state, instance] as const;
51
+ };
52
+
53
+ export interface FairysValtioFormAttrsNameOptions {
54
+ name?: string;
55
+ /**是否拼接父级字段名*/
56
+ isJoinParentField?: boolean;
57
+ }
58
+
59
+ /***获取属性名和路径*/
60
+ export const useFairysValtioFormAttrsName = (options: FairysValtioFormAttrsNameOptions = {}) => {
61
+ const { name, isJoinParentField = true } = options;
62
+ const formAttrsNameInstance = useFairysValtioFormParentAttrs();
63
+ const [state] = useFairysValtioFormParentAttrsState();
64
+ const parentName = state.name;
65
+ const _name = useMemo(
66
+ () => (isJoinParentField ? formateName(name, parentName) : name),
67
+ [name, parentName, isJoinParentField],
68
+ );
69
+ const _paths = useMemo(() => formatePath(_name), [_name]);
70
+ useMemo(() => formAttrsNameInstance.updatedName(_name), [_name]);
71
+
72
+ return {
73
+ formAttrsNameInstance,
74
+ parentName,
75
+ name: _name,
76
+ paths: _paths,
77
+ };
78
+ };