@fairys/valtio-form-basic 0.0.8 → 0.0.9

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.
@@ -2,13 +2,14 @@ import { MObject } from '../interface';
2
2
  import { FairysValtioFormInstance } from './instance';
3
3
  import { type ReactNode } from 'react';
4
4
  import { FairysValtioFormLayoutAttrsProps } from './layout';
5
+ import { RuleItem } from 'async-validator';
5
6
  export interface FairysValtioFormAttrsProps<T extends MObject<T> = object> extends FairysValtioFormLayoutAttrsProps {
6
7
  /**表单实例*/
7
8
  form?: FairysValtioFormInstance<T>;
8
9
  /**子元素*/
9
10
  children: ReactNode;
10
11
  /**表单项规则*/
11
- rules?: FairysValtioFormInstance<T>['rules'];
12
+ rules?: Record<PropertyKey, RuleItem[]>;
12
13
  /**表单初始值*/
13
14
  formData?: FairysValtioFormInstance<T>['state'];
14
15
  /**表单隐藏状态*/
@@ -62,5 +63,8 @@ export declare function useFairysValtioForm<T extends MObject<T> = object>(props
62
63
  formItemLabelStyle?: React.CSSProperties;
63
64
  formItemBodyClassName?: string;
64
65
  formItemBodyStyle?: React.CSSProperties;
65
- borderedType?: "bottom" | "body";
66
+ itemBorderType?: "bottom" | "body";
67
+ itemBorderColor?: React.CSSProperties["borderColor"];
68
+ isInvalidBorderRed?: boolean;
69
+ showColon?: boolean;
66
70
  };
@@ -3,9 +3,21 @@ import { MObject } from '../interface';
3
3
  import React from 'react';
4
4
  import { FairysValtioFormInstance } from './instance';
5
5
  import { FairysValtioFormLayoutContextOptions } from './layout';
6
+ import { FairysValtioFormParentAttrs } from './hooks';
7
+ import { RuleItem } from 'async-validator';
6
8
  export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
7
- /**表单项名称*/
8
- name: string;
9
+ /**
10
+ * 表单项名称 ,字段需要和存储的字段路径一致
11
+ *
12
+ * @example
13
+ * 路径中的值为 number 类型时,会创建一个空数组。路径中的值为 string 类型时,会创建一个空对象。最后一个直接赋值
14
+ *
15
+ * 默认:"name"
16
+ * 嵌套字段:"name.a.doc" ===> { name: { a: { doc: undefined } } }
17
+ * 嵌套字段:"name[1].a.doc" ===> { name: [{}, { a: { doc: undefined } }] }
18
+ * 嵌套字段:"name.a[2].doc" ===> { name: { a: [{}, {}, { doc: undefined }] } }
19
+ */
20
+ name?: string;
9
21
  /**表单项标签*/
10
22
  label?: string;
11
23
  /**传递组件字段*/
@@ -48,9 +60,17 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
48
60
  /**是否显示冒号*/
49
61
  showColon?: boolean;
50
62
  /**底部显示边框*/
51
- borderedType?: FairysValtioFormLayoutContextOptions['borderedType'];
63
+ itemBorderType?: FairysValtioFormLayoutContextOptions['itemBorderType'];
64
+ /**边框颜色*/
65
+ itemBorderColor?: React.CSSProperties['borderColor'];
66
+ /**是否校验失败时显示红色边框*/
67
+ isInvalidBorderRed?: boolean;
52
68
  /**输入框属性*/
53
69
  attrs?: any;
70
+ /**是否拼接父级字段名*/
71
+ isJoinParentField?: boolean;
72
+ /**校验规则*/
73
+ rules?: RuleItem[];
54
74
  }
55
75
  /**
56
76
  * 处理表单表单项属性
@@ -59,7 +79,7 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
59
79
  *
60
80
  * ```tsx
61
81
  import { Fragment } from 'react'
62
- import { useFairysValtioFormItemAttrs } from "@fairys/valtio-form"
82
+ import { useFairysValtioFormItemAttrs , FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
63
83
  import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
64
84
  export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
65
85
 
@@ -68,10 +88,11 @@ export const FormItem = (props: FormItemProps) => {
68
88
  const {
69
89
  itemClassName, itemStyle, containerClassName, itemLabelClassName, itemLabelStyle,
70
90
  itemBodyClassName, itemBodyStyle, itemInputClassName, itemExtraClassName, errorClassName, helpClassName,
71
- isInvalid, borderedType, children, error
91
+ isInvalid, itemBorderType, children, error,formAttrsNameInstance
72
92
  } = useFairysValtioFormItemAttrs(props)
73
93
 
74
94
  return (
95
+ <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
75
96
  <View className={itemClassName} style={itemStyle}>
76
97
  <View className={containerClassName}>
77
98
  <View className={itemLabelClassName} style={itemLabelStyle}>
@@ -82,12 +103,13 @@ export const FormItem = (props: FormItemProps) => {
82
103
  {children}
83
104
  </View>
84
105
  {extra ? <View className={itemExtraClassName}>{extra}</View> : <Fragment />}
85
- {borderedType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
106
+ {itemBorderType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
86
107
  </View>
87
108
  </View>
88
109
  {helpText ? <View className={helpClassName}>{helpText}</View> : <Fragment />}
89
- {isInvalid && borderedType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
110
+ {isInvalid && itemBorderType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
90
111
  </View>
112
+ </FairysValtioFormParentAttrsContext.Provider>
91
113
  );
92
114
  }
93
115
  * ```
@@ -98,31 +120,41 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
98
120
  /**表单项值*/
99
121
  value?: any;
100
122
  /**是否校验错误*/
101
- isInvalid?: boolean;
123
+ isInvalid: boolean;
102
124
  /**边框类型*/
103
- borderedType?: FairysValtioFormLayoutContextOptions['borderedType'];
125
+ itemBorderType: FairysValtioFormLayoutContextOptions['itemBorderType'];
104
126
  /**值改变事件*/
105
- onValueChange?: (event: any) => void;
127
+ onValueChange: (event: any) => void;
106
128
  /**当前表单项占据列数*/
107
- colSpan?: number;
129
+ colSpan: number;
108
130
  /**当前表单项占据行数*/
109
- rowSpan?: number;
131
+ rowSpan: number;
110
132
  /**列数*/
111
- colCount?: number;
133
+ colCount: number;
112
134
  /**标签显示模式*/
113
- labelMode?: FairysValtioFormLayoutContextOptions['labelMode'];
135
+ labelMode: FairysValtioFormLayoutContextOptions['labelMode'];
114
136
  /**错误提示位置*/
115
- errorLayout?: FairysValtioFormLayoutContextOptions['errorLayout'];
137
+ errorLayout: FairysValtioFormLayoutContextOptions['errorLayout'];
116
138
  /**是否必填*/
117
- isRequired?: boolean;
139
+ isRequired: boolean;
118
140
  /**表单状态*/
119
- state?: T;
141
+ state: T;
120
142
  /**错误状态*/
121
- errorState?: Record<PropertyKey, string[]>;
143
+ errorState: Record<PropertyKey, string[]>;
122
144
  /**表单实例*/
123
- formInstance?: FairysValtioFormInstance<T>;
145
+ formInstance: FairysValtioFormInstance<T>;
124
146
  /**错误信息*/
125
147
  error?: string[];
148
+ /**拼接父级字段名后得到的表单项名称*/
149
+ _name?: string;
150
+ /**表单项名称*/
151
+ name?: string;
152
+ /**表单项路径*/
153
+ paths?: (string | number)[];
154
+ /**父级字段名*/
155
+ parentName?: string;
156
+ /**表单属性名实例*/
157
+ formAttrsNameInstance: FairysValtioFormParentAttrs;
126
158
  /**表单项类名*/
127
159
  itemClassName: string;
128
160
  /**表单项样式*/
@@ -148,3 +180,36 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
148
180
  /**子元素*/
149
181
  children?: React.ReactNode;
150
182
  }
183
+ /**
184
+ * 没有样式的表单项属性,仅返回基础输入组件参数
185
+ *
186
+ * @example
187
+ *
188
+ *```tsx
189
+ import { Fragment } from 'react'
190
+ import { useFairysValtioFormItemAttrs, FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
191
+ import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
192
+ export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
193
+
194
+ export const FormItem = (props: FormItemProps) => {
195
+ const { children , formAttrsNameInstance } = useFairysValtioFormItemNoStyleAttrs(props)
196
+ return <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
197
+ {children}
198
+ </FairysValtioFormParentAttrsContext.Provider>
199
+ }
200
+ * ```
201
+ */
202
+ export declare function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = object>(props: FairysValtioFormItemAttrsProps<T>): {
203
+ value: unknown;
204
+ error: string[];
205
+ onValueChange: (event: any) => void;
206
+ state: T;
207
+ errorState: Record<PropertyKey, string[]>;
208
+ formInstance: FairysValtioFormInstance<T>;
209
+ _name: string;
210
+ name: string;
211
+ paths: (number | symbol)[] | (string | number)[];
212
+ parentName: string;
213
+ formAttrsNameInstance: FairysValtioFormParentAttrs;
214
+ children: string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode>;
215
+ };
@@ -1,11 +1,13 @@
1
- import react, { useMemo } from "react";
1
+ import react, { useEffect, useMemo } from "react";
2
2
  import clsx from "clsx";
3
3
  import { useFairysValtioFormInstanceContextState } from "./instance/index.js";
4
4
  import { useFairysValtioFormLayoutContext } from "./layout.js";
5
+ import { useFairysValtioFormAttrsName } from "./hooks/index.js";
6
+ import { get } from "./utils/index.js";
5
7
  function useFairysValtioFormItemAttrs(props) {
6
8
  const [layoutAttrs] = useFairysValtioFormLayoutContext();
7
9
  const colCount = layoutAttrs.colCount || 1;
8
- const parent_borderedType = layoutAttrs.borderedType || 'bottom';
10
+ const parent_borderedType = layoutAttrs.itemBorderType || 'bottom';
9
11
  const parent_errorLayout = layoutAttrs.errorLayout || 'right-bottom';
10
12
  const parent_formItemClassName = layoutAttrs.formItemClassName;
11
13
  const parent_formItemLabelClassName = layoutAttrs.formItemLabelClassName;
@@ -14,20 +16,34 @@ function useFairysValtioFormItemAttrs(props) {
14
16
  const parent_formItemBodyClassName = layoutAttrs.formItemBodyClassName;
15
17
  const parent_formItemBodyStyle = layoutAttrs.formItemBodyStyle;
16
18
  const parent_labelMode = layoutAttrs.labelMode || 'between';
17
- const { name, valuePropName = 'value', getValueFromEvent, formatValue, onAfterUpdate, trigger = 'onChange', className, style, labelClassName, labelStyle, bodyClassName, bodyStyle, children, labelMode = parent_labelMode, errorLayout = parent_errorLayout, colSpan = 1, rowSpan = 1, isRequired: _isRequired, borderedType = parent_borderedType, attrs = {}, showColon = false } = props;
19
+ const parent_itemBorderColor = layoutAttrs.itemBorderColor;
20
+ const parent_isInvalidBorderRed = layoutAttrs.isInvalidBorderRed;
21
+ const parent_showColon = layoutAttrs.showColon;
22
+ const { name, valuePropName = 'value', getValueFromEvent, formatValue, onAfterUpdate, trigger = 'onChange', className, style, labelClassName, labelStyle, bodyClassName, bodyStyle, children, labelMode = parent_labelMode, errorLayout = parent_errorLayout, colSpan = 1, rowSpan = 1, isRequired: _isRequired, itemBorderType = parent_borderedType, attrs = {}, showColon = parent_showColon, itemBorderColor = parent_itemBorderColor, isInvalidBorderRed = parent_isInvalidBorderRed, isJoinParentField = true, rules } = props;
23
+ const { name: _name, paths, parentName, formAttrsNameInstance } = useFairysValtioFormAttrsName({
24
+ name,
25
+ isJoinParentField
26
+ });
18
27
  const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState();
19
- const rules = formInstance.rules?.[name];
20
- const value = state[name];
21
- const error = errorState[name];
28
+ const value = useMemo(()=>get(state, paths), [
29
+ state,
30
+ paths
31
+ ]);
32
+ const error = errorState[_name];
33
+ formInstance.nameToPaths[_name] = paths;
34
+ if (Array.isArray(rules) && rules.length) formInstance.mountRules[_name] = rules;
35
+ useEffect(()=>()=>{
36
+ formInstance.removeRules(_name);
37
+ }, [
38
+ _name
39
+ ]);
22
40
  const onValueChange = (event)=>{
23
41
  let value = event;
24
42
  const target = event?.detail || event?.target;
25
43
  if ('function' == typeof getValueFromEvent) value = getValueFromEvent(event, formInstance);
26
44
  else if (event && target && 'object' == typeof target && valuePropName in target) value = target.valuePropName;
27
45
  if ('function' == typeof formatValue) value = formatValue(value, formInstance, event);
28
- formInstance.updated({
29
- [name]: value
30
- });
46
+ formInstance.updatedValueByPaths(_name, value);
31
47
  if ('function' == typeof onAfterUpdate) onAfterUpdate(value, formInstance, event);
32
48
  };
33
49
  const baseControl = {
@@ -51,13 +67,17 @@ function useFairysValtioFormItemAttrs(props) {
51
67
  error
52
68
  ]);
53
69
  const item_cls = useMemo(()=>clsx('fairys-valtio-form-item fairystaroform__p-_zkh1_4px_zhk2_ fairystaroform__text-_zkh1_12px_zhk2_ fairystaroform__relative fairystaroform__flex fairystaroform__flex-col fairystaroform__box-border fairystaroform__break-all', {
54
- 'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200': 'bottom' === borderedType,
70
+ 'fairys-valtio-form-item-invalid': isInvalid,
71
+ 'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && 'bottom' === itemBorderType,
72
+ 'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200': 'bottom' === itemBorderType,
55
73
  [labelMode]: labelMode
56
- }, className, parent_formItemClassName), [
74
+ }, parent_formItemClassName, className), [
57
75
  className,
58
76
  parent_formItemClassName,
59
77
  labelMode,
60
- borderedType
78
+ itemBorderType,
79
+ isInvalid,
80
+ isInvalidBorderRed
61
81
  ]);
62
82
  const itemContainer_cls = useMemo(()=>clsx('fairys-valtio-form-item-container fairystaroform__flex-1 fairystaroform__h-full fairystaroform__flex fairystaroform__box-border', {
63
83
  'fairystaroform__flex-row fairystaroform__items-center fairystaroform__justify-between fairystaroform__gap-_zkh1_8px_zhk2_': 'between' === labelMode,
@@ -83,12 +103,15 @@ function useFairysValtioFormItemAttrs(props) {
83
103
  'fairystaroform__flex-row fairystaroform__justify-start': 'left' === labelMode,
84
104
  'fairystaroform__flex-row fairystaroform__justify-end': 'between' === labelMode || 'top' === labelMode,
85
105
  'fairystaroform__flex-row': 'top' === labelMode,
86
- 'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200 ': 'body' === borderedType
87
- }, bodyClassName, parent_formItemBodyClassName), [
106
+ 'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200 ': 'body' === itemBorderType,
107
+ 'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && 'body' === itemBorderType
108
+ }, parent_formItemBodyClassName, bodyClassName), [
88
109
  bodyClassName,
89
110
  labelMode,
90
- borderedType,
91
- parent_formItemBodyClassName
111
+ itemBorderType,
112
+ parent_formItemBodyClassName,
113
+ isInvalid,
114
+ isInvalidBorderRed
92
115
  ]);
93
116
  const itemInput_cls = useMemo(()=>clsx('fairys-valtio-form-item-body fairystaroform__flex fairystaroform__flex-row fairystaroform__flex-1 fairystaroform__box-border', {
94
117
  'fairystaroform__justify-end fairystaroform__text-right': 'between' === labelMode,
@@ -122,7 +145,7 @@ function useFairysValtioFormItemAttrs(props) {
122
145
  return {
123
146
  value,
124
147
  isInvalid,
125
- borderedType,
148
+ itemBorderType,
126
149
  onValueChange,
127
150
  colSpan,
128
151
  rowSpan,
@@ -134,8 +157,16 @@ function useFairysValtioFormItemAttrs(props) {
134
157
  errorState,
135
158
  formInstance,
136
159
  error,
160
+ _name,
161
+ name,
162
+ paths,
163
+ parentName,
164
+ formAttrsNameInstance,
137
165
  itemClassName: item_cls,
138
166
  itemStyle: {
167
+ ...itemBorderColor && 'bottom' === itemBorderType ? {
168
+ borderBottomColor: itemBorderColor
169
+ } : {},
139
170
  ...parent_formItemStyle || {},
140
171
  ...styleBase,
141
172
  ...style || {}
@@ -148,6 +179,9 @@ function useFairysValtioFormItemAttrs(props) {
148
179
  },
149
180
  itemBodyClassName: itemBody_cls,
150
181
  itemBodyStyle: {
182
+ ...itemBorderColor && 'body' === itemBorderType ? {
183
+ borderBottomColor: itemBorderColor
184
+ } : {},
151
185
  ...parent_formItemBodyStyle || {},
152
186
  ...bodyStyle || {}
153
187
  },
@@ -160,4 +194,55 @@ function useFairysValtioFormItemAttrs(props) {
160
194
  }) : children
161
195
  };
162
196
  }
163
- export { useFairysValtioFormItemAttrs };
197
+ function useFairysValtioFormItemNoStyleAttrs(props) {
198
+ const { name, valuePropName = 'value', getValueFromEvent, formatValue, onAfterUpdate, trigger = 'onChange', children, attrs = {}, isJoinParentField = true, rules } = props;
199
+ const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState();
200
+ const { name: _name, paths, parentName, formAttrsNameInstance } = useFairysValtioFormAttrsName({
201
+ name,
202
+ isJoinParentField
203
+ });
204
+ const value = useMemo(()=>get(state, paths), [
205
+ state,
206
+ paths
207
+ ]);
208
+ const error = errorState[_name];
209
+ formInstance.nameToPaths[_name] = paths;
210
+ if (Array.isArray(rules) && rules.length) formInstance.mountRules[_name] = rules;
211
+ useEffect(()=>()=>{
212
+ formInstance.removeRules(_name);
213
+ }, [
214
+ _name
215
+ ]);
216
+ const onValueChange = (event)=>{
217
+ let value = event;
218
+ const target = event?.detail || event?.target;
219
+ if ('function' == typeof getValueFromEvent) value = getValueFromEvent(event, formInstance);
220
+ else if (event && target && 'object' == typeof target && valuePropName in target) value = target.valuePropName;
221
+ if ('function' == typeof formatValue) value = formatValue(value, formInstance, event);
222
+ formInstance.updatedValueByPaths(_name, value);
223
+ if ('function' == typeof onAfterUpdate) onAfterUpdate(value, formInstance, event);
224
+ };
225
+ const baseControl = {
226
+ ...attrs,
227
+ name,
228
+ [valuePropName]: value,
229
+ [trigger]: onValueChange
230
+ };
231
+ return {
232
+ value,
233
+ error,
234
+ onValueChange,
235
+ state,
236
+ errorState,
237
+ formInstance,
238
+ _name,
239
+ name,
240
+ paths,
241
+ parentName,
242
+ formAttrsNameInstance,
243
+ children: /*#__PURE__*/ react.isValidElement(children) ? /*#__PURE__*/ react.cloneElement(children, {
244
+ ...baseControl
245
+ }) : children
246
+ };
247
+ }
248
+ export { useFairysValtioFormItemAttrs, useFairysValtioFormItemNoStyleAttrs };
@@ -0,0 +1,34 @@
1
+ export interface FairysValtioFormParentAttrsState {
2
+ name?: string;
3
+ }
4
+ /***
5
+ * 父级属性
6
+ */
7
+ export declare class FairysValtioFormParentAttrs {
8
+ state: FairysValtioFormParentAttrsState;
9
+ updated: (attrs: Record<string, any>) => void;
10
+ /***更新父级字段值*/
11
+ updatedName: (name?: string, parentName?: string) => void;
12
+ }
13
+ /**初始化父级属性*/
14
+ export declare const useFairysValtioFormParentAttrs: (instance?: FairysValtioFormParentAttrs) => FairysValtioFormParentAttrs;
15
+ /***父级属性上下文*/
16
+ export declare const FairysValtioFormParentAttrsContext: import("react").Context<FairysValtioFormParentAttrs>;
17
+ /***获取父级属性实例*/
18
+ export declare const useFairysValtioFormParentAttrsContext: () => FairysValtioFormParentAttrs;
19
+ /***获取父级属性状态*/
20
+ export declare const useFairysValtioFormParentAttrsState: () => readonly [{
21
+ readonly name?: string;
22
+ }, FairysValtioFormParentAttrs];
23
+ export interface FairysValtioFormAttrsNameOptions {
24
+ name?: string;
25
+ /**是否拼接父级字段名*/
26
+ isJoinParentField?: boolean;
27
+ }
28
+ /***获取属性名和路径*/
29
+ export declare const useFairysValtioFormAttrsName: (options?: FairysValtioFormAttrsNameOptions) => {
30
+ formAttrsNameInstance: FairysValtioFormParentAttrs;
31
+ parentName: string;
32
+ name: string;
33
+ paths: (number | symbol)[] | (string | number)[];
34
+ };
@@ -0,0 +1,57 @@
1
+ import { createContext, useContext, useMemo, useRef } from "react";
2
+ import { proxy, useSnapshot } from "valtio";
3
+ import { formateName, formatePath } from "../utils/index.js";
4
+ class FairysValtioFormParentAttrs {
5
+ state = proxy({
6
+ name: ''
7
+ });
8
+ updated = (attrs)=>{
9
+ this.state = {
10
+ ...this.state,
11
+ ...attrs
12
+ };
13
+ };
14
+ updatedName = (name, parentName)=>{
15
+ this.state.name = formateName(name, parentName);
16
+ };
17
+ }
18
+ const useFairysValtioFormParentAttrs = (instance)=>{
19
+ const parentAttrs = useRef();
20
+ if (!parentAttrs.current) if (instance) parentAttrs.current = instance;
21
+ else parentAttrs.current = new FairysValtioFormParentAttrs();
22
+ return parentAttrs.current;
23
+ };
24
+ const FairysValtioFormParentAttrsContext = /*#__PURE__*/ createContext(new FairysValtioFormParentAttrs());
25
+ const useFairysValtioFormParentAttrsContext = ()=>useContext(FairysValtioFormParentAttrsContext);
26
+ const useFairysValtioFormParentAttrsState = ()=>{
27
+ const instance = useFairysValtioFormParentAttrsContext();
28
+ const state = useSnapshot(instance.state);
29
+ return [
30
+ state,
31
+ instance
32
+ ];
33
+ };
34
+ const useFairysValtioFormAttrsName = (options = {})=>{
35
+ const { name, isJoinParentField = true } = options;
36
+ const formAttrsNameInstance = useFairysValtioFormParentAttrs();
37
+ const [state] = useFairysValtioFormParentAttrsState();
38
+ const parentName = state.name;
39
+ const _name = useMemo(()=>isJoinParentField ? formateName(name, parentName) : name, [
40
+ name,
41
+ parentName,
42
+ isJoinParentField
43
+ ]);
44
+ const _paths = useMemo(()=>formatePath(_name), [
45
+ _name
46
+ ]);
47
+ useMemo(()=>formAttrsNameInstance.updatedName(_name), [
48
+ _name
49
+ ]);
50
+ return {
51
+ formAttrsNameInstance,
52
+ parentName,
53
+ name: _name,
54
+ paths: _paths
55
+ };
56
+ };
57
+ export { FairysValtioFormParentAttrs, FairysValtioFormParentAttrsContext, useFairysValtioFormAttrsName, useFairysValtioFormParentAttrs, useFairysValtioFormParentAttrsContext, useFairysValtioFormParentAttrsState };
@@ -22,6 +22,11 @@ export declare class FairysValtioFormInstance<T extends MObject<T> = Record<stri
22
22
  * @param isValidate 是否验证(可选)
23
23
  */
24
24
  updated: <M = T>(state: Partial<M>, isValidate?: boolean) => void;
25
+ /**根据路径设置值
26
+ * @param path 值路径
27
+ * @param value 值
28
+ */
29
+ updatedValueByPaths: (path: PropertyKey, value: any) => void;
25
30
  /**
26
31
  * 更新行数据的隐藏信息
27
32
  * @param objectHideInfo 行数据隐藏信息对象
@@ -44,12 +49,15 @@ export declare class FairysValtioFormInstance<T extends MObject<T> = Record<stri
44
49
  * 清理所有数据
45
50
  */
46
51
  clear: () => void;
47
- /**列规则 */
48
- rules: Record<PropertyKey, ((formData: T, instance: FairysValtioFormInstance<T>) => RuleItem[] | Promise<RuleItem[]>) | RuleItem[]>;
49
- /**规则验证
50
- * @param fields 列字段数组(可选)
51
- * @param isReturn 是否返回验证结果(可选)
52
- */
52
+ /**由表单项挂载规则,(根据表单项的字段存储路径对应校验规则)*/
53
+ mountRules: Record<PropertyKey, RuleItem[]>;
54
+ /**移除表单项挂载规则*/
55
+ removeRules: (name: PropertyKey) => void;
56
+ /**表单项规则*/
57
+ rules: Record<PropertyKey, RuleItem[]>;
58
+ /**表单项名称到路径映射*/
59
+ nameToPaths: Record<PropertyKey, PropertyKey[]>;
60
+ /**验证表单项规则*/
53
61
  validate: (fields?: PropertyKey[], isReturn?: boolean) => Promise<ValidateFieldsError | Values>;
54
62
  }
55
63
  /**声明实例*/
@@ -2,6 +2,7 @@ import { createContext, useContext, useRef } from "react";
2
2
  import { proxy, ref as external_valtio_ref, snapshot, useSnapshot } from "valtio";
3
3
  import async_validator from "async-validator";
4
4
  import { copy } from "fast-copy";
5
+ import { formatePath, get, set } from "../utils/index.js";
5
6
  class FairysValtioFormInstance {
6
7
  state = proxy({});
7
8
  errorState = proxy({});
@@ -21,6 +22,12 @@ class FairysValtioFormInstance {
21
22
  }
22
23
  if (isValidate) this.validate(keys, false);
23
24
  };
25
+ updatedValueByPaths = (path, value)=>{
26
+ set(this.state, formatePath(path), value);
27
+ this.validate([
28
+ path
29
+ ], false);
30
+ };
24
31
  updatedHideInfo = (objectHideInfo)=>{
25
32
  const keys = Object.keys(objectHideInfo);
26
33
  for(let index = 0; index < keys.length; index++){
@@ -60,36 +67,49 @@ class FairysValtioFormInstance {
60
67
  this.errorState = proxy({});
61
68
  this.hideState = proxy({});
62
69
  };
70
+ mountRules = {};
71
+ removeRules = (name)=>{
72
+ delete this.mountRules[name];
73
+ };
63
74
  rules = {};
75
+ nameToPaths = {};
64
76
  validate = async (fields, isReturn = true)=>{
65
- let _fields = fields;
77
+ const rules = {
78
+ ...this.rules,
79
+ ...this.mountRules
80
+ };
66
81
  const _formData = snapshot(this.state);
67
- if (!this.rules) return Promise.resolve({
68
- ..._formData
69
- });
70
- const rules = {};
71
- let isNeedValidate = false;
72
- if (!fields || Array.isArray(fields) && 0 === fields.length) _fields = Object.keys(this.rules);
73
- for(let index = 0; index < _fields.length; index++){
74
- isNeedValidate = true;
75
- const element = _fields[index];
76
- const rule = this.rules[element];
77
- if ('function' == typeof rule) {
78
- const _rules = await rule(_formData, this);
79
- rules[element] = _rules;
80
- } else if (Array.isArray(rule)) rules[element] = rule;
81
- }
82
- if (!isNeedValidate) {
83
- console.warn('no rules to validate');
84
- return Promise.resolve({
85
- ..._formData
86
- });
82
+ const _values = {};
83
+ let _fields = Object.keys(rules);
84
+ let _lastRules = {};
85
+ let isPropsFields = false;
86
+ if (Array.isArray(fields) && fields.length) {
87
+ _fields = [
88
+ ...fields
89
+ ];
90
+ isPropsFields = true;
91
+ for(let index = 0; index < fields.length; index++){
92
+ const field = fields[index];
93
+ const paths = this.nameToPaths[field];
94
+ _lastRules[field] = rules[field];
95
+ _values[field] = get(_formData, paths ? paths : formatePath(field));
96
+ }
97
+ } else {
98
+ isPropsFields = false;
99
+ _lastRules = {
100
+ ...rules
101
+ };
102
+ for(let index = 0; index < _fields.length; index++){
103
+ const field = _fields[index];
104
+ const paths = this.nameToPaths[field];
105
+ _values[field] = get(_formData, paths);
106
+ }
87
107
  }
88
108
  return new Promise((resolve, reject)=>{
89
109
  new async_validator({
90
110
  ...rules
91
111
  }).validate({
92
- ..._formData
112
+ ..._values
93
113
  }, (errors, fields)=>{
94
114
  for(let index = 0; index < _fields.length; index++){
95
115
  const field = _fields[index];
@@ -101,7 +121,11 @@ class FairysValtioFormInstance {
101
121
  errors,
102
122
  fields
103
123
  });
104
- else resolve(fields);
124
+ else isPropsFields ? resolve({
125
+ ...fields
126
+ }) : resolve({
127
+ ..._formData
128
+ });
105
129
  });
106
130
  });
107
131
  };
@@ -23,7 +23,13 @@ export interface FairysValtioFormLayoutContextOptions {
23
23
  /**
24
24
  * 底部边框类型
25
25
  */
26
- borderedType?: 'bottom' | 'body';
26
+ itemBorderType?: 'bottom' | 'body';
27
+ /**边框颜色*/
28
+ itemBorderColor?: React.CSSProperties['borderColor'];
29
+ /**是否校验失败时显示红色边框*/
30
+ isInvalidBorderRed?: boolean;
31
+ /**是否显示冒号*/
32
+ showColon?: boolean;
27
33
  }
28
34
  export interface FairysValtioFormLayoutAttrsProps extends FairysValtioFormLayoutContextOptions {
29
35
  /**
@@ -2645,7 +2651,10 @@ export declare const useFairysValtioFormLayoutContext: () => readonly [{
2645
2651
  readonly colorRendering?: import("csstype").Property.ColorRendering | undefined;
2646
2652
  readonly glyphOrientationVertical?: import("csstype").Property.GlyphOrientationVertical | undefined;
2647
2653
  };
2648
- readonly borderedType?: "bottom" | "body";
2654
+ readonly itemBorderType?: "bottom" | "body";
2655
+ readonly itemBorderColor?: React.CSSProperties["borderColor"];
2656
+ readonly isInvalidBorderRed?: boolean;
2657
+ readonly showColon?: boolean;
2649
2658
  }, FairysValtioFormLayoutInstance];
2650
2659
  /**
2651
2660
  * 布局属性处理
@@ -2706,7 +2715,7 @@ export interface FairysValtioFormLayoutAttrsReturn {
2706
2715
  /**
2707
2716
  * 底部边框类型
2708
2717
  */
2709
- borderedType: string;
2718
+ itemBorderType: string;
2710
2719
  /**表单布局实例*/
2711
2720
  formLayoutInstance: FairysValtioFormLayoutInstance;
2712
2721
  /**布局ClassName*/