@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.
@@ -6,7 +6,7 @@ class FairysValtioFormLayoutInstance {
6
6
  colCount: 1,
7
7
  errorLayout: 'right-bottom',
8
8
  labelMode: 'between',
9
- borderedType: 'bottom'
9
+ itemBorderType: 'bottom'
10
10
  });
11
11
  updated = (options = {})=>{
12
12
  const keys = Object.keys(options);
@@ -43,8 +43,11 @@ function useFairysValtioFormLayoutAttrs(props) {
43
43
  const parent_formItemLabelStyle = state.formItemLabelStyle;
44
44
  const parent_formItemBodyClassName = state.formItemBodyClassName;
45
45
  const parent_formItemBodyStyle = state.formItemBodyStyle;
46
- const parent_borderedType = state.borderedType || 'bottom';
47
- const { colCount = parent_colCount, errorLayout = parent_errorLayout, labelMode = parent_labelMode, formItemClassName = parent_formItemClassName, formItemStyle = parent_formItemStyle, formItemLabelClassName = parent_formItemLabelClassName, formItemLabelStyle = parent_formItemLabelStyle, formItemBodyClassName = parent_formItemBodyClassName, formItemBodyStyle = parent_formItemBodyStyle, borderedType = parent_borderedType, lastItemBordered = true, gap, isAllColSpan = false, className, style, headerClassName, headerStyle, bodyClassName, bodyStyle, bordered, boxShadow } = props;
46
+ const parent_borderedType = state.itemBorderType || 'bottom';
47
+ const parent_itemBorderColor = state.itemBorderColor;
48
+ const parent_isInvalidBorderRed = state.isInvalidBorderRed;
49
+ const parent_showColon = state.showColon;
50
+ const { colCount = parent_colCount, errorLayout = parent_errorLayout, labelMode = parent_labelMode, formItemClassName = parent_formItemClassName, formItemStyle = parent_formItemStyle, formItemLabelClassName = parent_formItemLabelClassName, formItemLabelStyle = parent_formItemLabelStyle, formItemBodyClassName = parent_formItemBodyClassName, formItemBodyStyle = parent_formItemBodyStyle, itemBorderType = parent_borderedType, itemBorderColor = parent_itemBorderColor, lastItemBordered = true, isInvalidBorderRed = parent_isInvalidBorderRed, showColon = parent_showColon, gap, isAllColSpan = false, className, style, headerClassName, headerStyle, bodyClassName, bodyStyle, bordered, boxShadow } = props;
48
51
  useMemo(()=>formLayoutInstance.updated({
49
52
  colCount,
50
53
  errorLayout,
@@ -55,7 +58,10 @@ function useFairysValtioFormLayoutAttrs(props) {
55
58
  formItemLabelStyle,
56
59
  formItemBodyClassName,
57
60
  formItemBodyStyle,
58
- borderedType
61
+ itemBorderType,
62
+ itemBorderColor,
63
+ isInvalidBorderRed,
64
+ showColon
59
65
  }), [
60
66
  colCount,
61
67
  errorLayout,
@@ -66,11 +72,14 @@ function useFairysValtioFormLayoutAttrs(props) {
66
72
  formItemLabelStyle,
67
73
  formItemBodyClassName,
68
74
  formItemBodyStyle,
69
- borderedType
75
+ itemBorderType,
76
+ itemBorderColor,
77
+ isInvalidBorderRed,
78
+ showColon
70
79
  ]);
71
- const layoutCls = useMemo(()=>clsx("fairys-valtio-form-layout fairystaroform__text-_zkh1_12px_zhk2_ fairystaroform__w-full fairystaroform__box-border fairystaroform__rounded-md", {
80
+ const layoutCls = useMemo(()=>clsx("fairys-valtio-form-layout fairystaroform__text-_zkh1_12px_zhk2_ fairystaroform__w-full fairystaroform__box-border fairystaroform__rounded-_zkh1_4px_zhk2_", {
72
81
  'fairys-valtio-form-layout-all-col-span': isAllColSpan,
73
- 'fairys-taro-form-valtio-layout-box-shadow': boxShadow,
82
+ 'fairys-valtio-form-layout-box-shadow': boxShadow,
74
83
  'fairystaroform__border fairystaroform__border-solid fairystaroform__border-gray-200': bordered,
75
84
  'fairys-valtio-form-layout-last-item-no-border': !lastItemBordered
76
85
  }, className), [
@@ -107,7 +116,7 @@ function useFairysValtioFormLayoutAttrs(props) {
107
116
  colCount,
108
117
  errorLayout,
109
118
  labelMode,
110
- borderedType,
119
+ itemBorderType,
111
120
  formLayoutInstance,
112
121
  layoutName: layoutCls,
113
122
  layoutStyle: style,
@@ -0,0 +1,24 @@
1
+ /***
2
+ * 设置值
3
+ * @param object 任意对象
4
+ * @param paths 值路径
5
+ * @param nextValue 新值
6
+ *
7
+ * @description
8
+ * 值不存在时,当 paths 路径中的值为 number 类型时,会创建一个空数组。当 paths 路径中的值为 string 类型时,会创建一个空对象。
9
+ */
10
+ export declare function set<T>(state: any, paths: PropertyKey[], nextValue: T): any;
11
+ /***
12
+ * 获取值
13
+ * @param value 任意值
14
+ * @param segments 键路径
15
+ */
16
+ export declare function get<TDefault = unknown>(value: any, segments: PropertyKey[]): TDefault;
17
+ /***
18
+ * 格式化路径,将路径中的数组索引转换为数字
19
+ * @param path 路径
20
+ * @returns 格式化后的路径
21
+ */
22
+ export declare function formatePath(path: PropertyKey): (number | symbol)[] | (string | number)[];
23
+ /**格式化属性名*/
24
+ export declare function formateName(name?: string, parentName?: string): string;
@@ -0,0 +1,60 @@
1
+ function set(state, paths, nextValue) {
2
+ const _keys = [
3
+ ...paths
4
+ ];
5
+ let current = state;
6
+ const length = _keys.length - 1;
7
+ for(let i = 0; i <= length; i++){
8
+ const key = _keys[i];
9
+ const _current = current[key];
10
+ const nextKey = _keys[i + 1];
11
+ if (void 0 === _current && 'number' == typeof nextKey) current[key] = [];
12
+ else if (void 0 === _current && 'string' == typeof nextKey) current[key] = {};
13
+ if (i === length) current[key] = nextValue;
14
+ else current = current[key];
15
+ }
16
+ return state;
17
+ }
18
+ function get(value, segments) {
19
+ let current = value;
20
+ for (const key of segments)current = current?.[key];
21
+ return current;
22
+ }
23
+ function formatePath(path) {
24
+ if ('string' != typeof path) return [
25
+ path
26
+ ];
27
+ return path.split(/[\.]/g).reduce((pre, next)=>{
28
+ if (/\[[0-9]+\]$/.test(next)) {
29
+ const _next = next.split(/\[/);
30
+ let _nextValue = [];
31
+ for(let index = 0; index < _next.length; index++){
32
+ const element = _next[index];
33
+ if (/\]$/.test(element)) {
34
+ const _v = element.replace(/\]$/, '');
35
+ const v = Number.parseInt(_v);
36
+ if (_v.length !== `${v}`.length || Number.isNaN(v)) _nextValue.push(_v);
37
+ else _nextValue.push(v);
38
+ } else _nextValue.push(element);
39
+ }
40
+ return [
41
+ ...pre,
42
+ ..._nextValue
43
+ ];
44
+ }
45
+ return [
46
+ ...pre,
47
+ next
48
+ ];
49
+ }, []).map((item)=>{
50
+ if ('string' == typeof item) return item.trim();
51
+ return item;
52
+ }).filter((item)=>'' !== item);
53
+ }
54
+ function formateName(name, parentName) {
55
+ if (parentName && name) return parentName + '.' + name;
56
+ if (parentName) return parentName;
57
+ if (name) return name;
58
+ return '';
59
+ }
60
+ export { formateName, formatePath, get, set };
package/esm/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './form/hooks';
1
2
  export * from './form/instance';
2
3
  export * from './form/layout';
3
4
  export * from './form/form';
package/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./form/hooks/index.js";
1
2
  export * from "./form/instance/index.js";
2
3
  export * from "./form/layout.js";
3
4
  export * from "./form/form.js";
@@ -166,8 +166,8 @@
166
166
  border-bottom-color: rgb(229 231 235 / var(--un-border-bottom-opacity));
167
167
  }
168
168
 
169
- .fairystaroform__rounded-md {
170
- border-radius: .375rem;
169
+ .fairystaroform__rounded-_zkh1_4px_zhk2_ {
170
+ border-radius: 4px;
171
171
  }
172
172
 
173
173
  .fairystaroform__border-solid {
@@ -248,11 +248,11 @@
248
248
  display: inline-block;
249
249
  }
250
250
 
251
- .fairys-valtio-form-layout.fairys-form-layout-all-col-span {
251
+ .fairys-valtio-form-layout.fairys-valtio-form-layout-all-col-span {
252
252
  grid-column: 1 / -1;
253
253
  }
254
254
 
255
- .fairys-valtio-form-layout.fairys-form-layout-box-shadow {
255
+ .fairys-valtio-form-layout.fairys-valtio-form-layout-box-shadow {
256
256
  box-shadow: 0 6px 16px -8px #00000014, 0 9px 28px #0000000d, 0 12px 48px 16px #00000008;
257
257
  }
258
258
 
@@ -260,7 +260,11 @@
260
260
  margin-top: 12px;
261
261
  }
262
262
 
263
- .fairys-valtio-form-layout-last-item-no-border > .fairys-valtio-form-layout-body > .fairys-valtio-form-item:last-child, .fairys-valtio-form-layout-last-item-no-border > .fairys-valtio-form-layout-body > .fairys-valtio-form-item:last-child > .fairys-valtio-form-item-container > .fairys-valtio-form-item-body {
263
+ .fairys-valtio-form-layout-last-item-no-border > .fairys-valtio-form-layout-body > .fairys-valtio-form-item:last-child:not(.fairys-valtio-form-item-invalid-border-red), .fairys-valtio-form-layout-last-item-no-border > .fairys-valtio-form-layout-body > .fairys-valtio-form-item:last-child > .fairys-valtio-form-item-container > .fairys-valtio-form-item-body:not(.fairys-valtio-form-item-invalid-border-red) {
264
264
  border-bottom: 0;
265
265
  }
266
266
 
267
+ .fairys-valtio-form-item-invalid-border-red {
268
+ border-bottom-color: red !important;
269
+ }
270
+
package/lib/index.js CHANGED
@@ -6,6 +6,9 @@ var __webpack_modules__ = {
6
6
  "./form/form": function(module) {
7
7
  module.exports = require("./form/form.js");
8
8
  },
9
+ "./form/hooks": function(module) {
10
+ module.exports = require("./form/hooks/index.js");
11
+ },
9
12
  "./form/instance": function(module) {
10
13
  module.exports = require("./form/instance/index.js");
11
14
  },
@@ -56,28 +59,34 @@ function __webpack_require__(moduleId) {
56
59
  var __webpack_exports__ = {};
57
60
  (()=>{
58
61
  __webpack_require__.r(__webpack_exports__);
59
- var _form_instance__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./form/instance");
62
+ var _form_hooks__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./form/hooks");
63
+ var __WEBPACK_REEXPORT_OBJECT__ = {};
64
+ for(var __WEBPACK_IMPORT_KEY__ in _form_hooks__WEBPACK_IMPORTED_MODULE_0__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
65
+ return _form_hooks__WEBPACK_IMPORTED_MODULE_0__[key];
66
+ }).bind(0, __WEBPACK_IMPORT_KEY__);
67
+ __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
68
+ var _form_instance__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./form/instance");
60
69
  var __WEBPACK_REEXPORT_OBJECT__ = {};
61
- for(var __WEBPACK_IMPORT_KEY__ in _form_instance__WEBPACK_IMPORTED_MODULE_0__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
62
- return _form_instance__WEBPACK_IMPORTED_MODULE_0__[key];
70
+ for(var __WEBPACK_IMPORT_KEY__ in _form_instance__WEBPACK_IMPORTED_MODULE_1__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
71
+ return _form_instance__WEBPACK_IMPORTED_MODULE_1__[key];
63
72
  }).bind(0, __WEBPACK_IMPORT_KEY__);
64
73
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
65
- var _form_layout__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./form/layout");
74
+ var _form_layout__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./form/layout");
66
75
  var __WEBPACK_REEXPORT_OBJECT__ = {};
67
- for(var __WEBPACK_IMPORT_KEY__ in _form_layout__WEBPACK_IMPORTED_MODULE_1__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
68
- return _form_layout__WEBPACK_IMPORTED_MODULE_1__[key];
76
+ for(var __WEBPACK_IMPORT_KEY__ in _form_layout__WEBPACK_IMPORTED_MODULE_2__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
77
+ return _form_layout__WEBPACK_IMPORTED_MODULE_2__[key];
69
78
  }).bind(0, __WEBPACK_IMPORT_KEY__);
70
79
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
71
- var _form_form__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./form/form");
80
+ var _form_form__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__("./form/form");
72
81
  var __WEBPACK_REEXPORT_OBJECT__ = {};
73
- for(var __WEBPACK_IMPORT_KEY__ in _form_form__WEBPACK_IMPORTED_MODULE_2__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
74
- return _form_form__WEBPACK_IMPORTED_MODULE_2__[key];
82
+ for(var __WEBPACK_IMPORT_KEY__ in _form_form__WEBPACK_IMPORTED_MODULE_3__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
83
+ return _form_form__WEBPACK_IMPORTED_MODULE_3__[key];
75
84
  }).bind(0, __WEBPACK_IMPORT_KEY__);
76
85
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
77
- var _form_form_item__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__("./form/form.item");
86
+ var _form_form_item__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__("./form/form.item");
78
87
  var __WEBPACK_REEXPORT_OBJECT__ = {};
79
- for(var __WEBPACK_IMPORT_KEY__ in _form_form_item__WEBPACK_IMPORTED_MODULE_3__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
80
- return _form_form_item__WEBPACK_IMPORTED_MODULE_3__[key];
88
+ for(var __WEBPACK_IMPORT_KEY__ in _form_form_item__WEBPACK_IMPORTED_MODULE_4__)if ("default" !== __WEBPACK_IMPORT_KEY__) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = (function(key) {
89
+ return _form_form_item__WEBPACK_IMPORTED_MODULE_4__[key];
81
90
  }).bind(0, __WEBPACK_IMPORT_KEY__);
82
91
  __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);
83
92
  })();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "author": "SunLxy <1011771396@qq.com>",
4
4
  "description": "使用 valtio 实现的表单基础库, 使其更加便捷,同时支持`PC`、`H5`、`Taro`,同时也更加灵活。",
5
5
  "homepage": "https://github.com/autumn-fairy-tales/fairys-taro-react",
6
- "version": "0.0.8",
6
+ "version": "0.0.9",
7
7
  "main": "lib/index.js",
8
8
  "types": "esm/index.d.ts",
9
9
  "module": "esm/index.js",
@@ -35,4 +35,4 @@
35
35
  "@types/react": "~18.2.21",
36
36
  "react": "^18.0.0"
37
37
  }
38
- }
38
+ }
@@ -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
  /**传递组件字段*/
@@ -51,9 +64,17 @@ 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;
55
72
  /**输入框属性*/
56
73
  attrs?: any;
74
+ /**是否拼接父级字段名*/
75
+ isJoinParentField?: boolean;
76
+ /**校验规则*/
77
+ rules?: RuleItem[];
57
78
  }
58
79
 
59
80
  /**
@@ -63,7 +84,7 @@ export interface FairysValtioFormItemAttrsProps<T extends MObject<T> = object> {
63
84
  *
64
85
  * ```tsx
65
86
  import { Fragment } from 'react'
66
- import { useFairysValtioFormItemAttrs } from "@fairys/valtio-form"
87
+ import { useFairysValtioFormItemAttrs , FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
67
88
  import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
68
89
  export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
69
90
 
@@ -72,10 +93,11 @@ export const FormItem = (props: FormItemProps) => {
72
93
  const {
73
94
  itemClassName, itemStyle, containerClassName, itemLabelClassName, itemLabelStyle,
74
95
  itemBodyClassName, itemBodyStyle, itemInputClassName, itemExtraClassName, errorClassName, helpClassName,
75
- isInvalid, borderedType, children, error
96
+ isInvalid, itemBorderType, children, error,formAttrsNameInstance
76
97
  } = useFairysValtioFormItemAttrs(props)
77
98
 
78
99
  return (
100
+ <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
79
101
  <View className={itemClassName} style={itemStyle}>
80
102
  <View className={containerClassName}>
81
103
  <View className={itemLabelClassName} style={itemLabelStyle}>
@@ -86,12 +108,13 @@ export const FormItem = (props: FormItemProps) => {
86
108
  {children}
87
109
  </View>
88
110
  {extra ? <View className={itemExtraClassName}>{extra}</View> : <Fragment />}
89
- {borderedType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
111
+ {itemBorderType === 'body' && isInvalid ? <View className={errorClassName}>{error}</View> : <Fragment />}
90
112
  </View>
91
113
  </View>
92
114
  {helpText ? <View className={helpClassName}>{helpText}</View> : <Fragment />}
93
- {isInvalid && borderedType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
115
+ {isInvalid && itemBorderType !== 'body' ? <View className={errorClassName}>{error}</View> : <Fragment />}
94
116
  </View>
117
+ </FairysValtioFormParentAttrsContext.Provider>
95
118
  );
96
119
  }
97
120
  * ```
@@ -100,7 +123,7 @@ export const FormItem = (props: FormItemProps) => {
100
123
  export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(props: FairysValtioFormItemAttrsProps<T>) {
101
124
  const [layoutAttrs] = useFairysValtioFormLayoutContext();
102
125
  const colCount = layoutAttrs.colCount || 1;
103
- const parent_borderedType = layoutAttrs.borderedType || 'bottom';
126
+ const parent_borderedType = layoutAttrs.itemBorderType || 'bottom';
104
127
  const parent_errorLayout = layoutAttrs.errorLayout || 'right-bottom';
105
128
  const parent_formItemClassName = layoutAttrs.formItemClassName;
106
129
  const parent_formItemLabelClassName = layoutAttrs.formItemLabelClassName;
@@ -109,6 +132,10 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
109
132
  const parent_formItemBodyClassName = layoutAttrs.formItemBodyClassName;
110
133
  const parent_formItemBodyStyle = layoutAttrs.formItemBodyStyle;
111
134
  const parent_labelMode = layoutAttrs.labelMode || 'between';
135
+ const parent_itemBorderColor = layoutAttrs.itemBorderColor;
136
+ const parent_isInvalidBorderRed = layoutAttrs.isInvalidBorderRed;
137
+ const parent_showColon = layoutAttrs.showColon;
138
+
112
139
  const {
113
140
  name,
114
141
  valuePropName = 'value',
@@ -128,14 +155,34 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
128
155
  colSpan = 1,
129
156
  rowSpan = 1,
130
157
  isRequired: _isRequired,
131
- borderedType = parent_borderedType,
158
+ itemBorderType = parent_borderedType,
132
159
  attrs = {},
133
- showColon = false,
160
+ showColon = parent_showColon,
161
+ itemBorderColor = parent_itemBorderColor,
162
+ isInvalidBorderRed = parent_isInvalidBorderRed,
163
+ isJoinParentField = true,
164
+ rules,
134
165
  } = props;
166
+
167
+ const {
168
+ name: _name,
169
+ paths,
170
+ parentName,
171
+ formAttrsNameInstance,
172
+ } = useFairysValtioFormAttrsName({ name, isJoinParentField });
135
173
  const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
136
- const rules = formInstance.rules?.[name];
137
- const value = state[name];
138
- const error = errorState[name];
174
+ const value = useMemo(() => get(state, paths), [state, paths]);
175
+ const error = errorState[_name];
176
+ formInstance.nameToPaths[_name] = paths;
177
+ /**挂载校验规则*/
178
+ if (Array.isArray(rules) && rules.length) {
179
+ formInstance.mountRules[_name] = rules;
180
+ }
181
+ useEffect(() => {
182
+ return () => {
183
+ formInstance.removeRules(_name);
184
+ };
185
+ }, [_name]);
139
186
 
140
187
  const onValueChange = (event: any) => {
141
188
  let value = event;
@@ -148,7 +195,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
148
195
  if (typeof formatValue === 'function') {
149
196
  value = formatValue(value, formInstance, event);
150
197
  }
151
- formInstance.updated({ [name]: value });
198
+ formInstance.updatedValueByPaths(_name, value);
152
199
  if (typeof onAfterUpdate === 'function') {
153
200
  onAfterUpdate(value, formInstance, event);
154
201
  }
@@ -185,14 +232,16 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
185
232
  return clsx(
186
233
  'fairys-valtio-form-item fairystaroform__p-[4px] fairystaroform__text-[12px] fairystaroform__relative fairystaroform__flex fairystaroform__flex-col fairystaroform__box-border fairystaroform__break-all',
187
234
  {
235
+ 'fairys-valtio-form-item-invalid': isInvalid,
236
+ 'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && itemBorderType === 'bottom',
188
237
  'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200':
189
- borderedType === 'bottom',
238
+ itemBorderType === 'bottom',
190
239
  [labelMode]: labelMode,
191
240
  },
192
- className,
193
241
  parent_formItemClassName,
242
+ className,
194
243
  );
195
- }, [className, parent_formItemClassName, labelMode, borderedType]);
244
+ }, [className, parent_formItemClassName, labelMode, itemBorderType, isInvalid, isInvalidBorderRed]);
196
245
 
197
246
  /**表单项容器类名*/
198
247
  const itemContainer_cls = useMemo(() => {
@@ -235,12 +284,13 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
235
284
  'fairystaroform__flex-row fairystaroform__justify-end': labelMode === 'between' || labelMode === 'top',
236
285
  'fairystaroform__flex-row': labelMode === 'top',
237
286
  'fairystaroform__border-b fairystaroform__border-b-solid fairystaroform__border-b-gray-200 ':
238
- borderedType === 'body',
287
+ itemBorderType === 'body',
288
+ 'fairys-valtio-form-item-invalid-border-red': isInvalid && isInvalidBorderRed && itemBorderType === 'body',
239
289
  },
240
- bodyClassName,
241
290
  parent_formItemBodyClassName,
291
+ bodyClassName,
242
292
  );
243
- }, [bodyClassName, labelMode, borderedType, parent_formItemBodyClassName]);
293
+ }, [bodyClassName, labelMode, itemBorderType, parent_formItemBodyClassName, isInvalid, isInvalidBorderRed]);
244
294
 
245
295
  // 表单项输入类名
246
296
  const itemInput_cls = useMemo(() => {
@@ -297,7 +347,7 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
297
347
  return {
298
348
  value,
299
349
  isInvalid,
300
- borderedType,
350
+ itemBorderType,
301
351
  onValueChange,
302
352
  colSpan,
303
353
  rowSpan,
@@ -309,14 +359,28 @@ export function useFairysValtioFormItemAttrs<T extends MObject<T> = object>(prop
309
359
  errorState,
310
360
  formInstance,
311
361
  error,
362
+ _name,
363
+ name,
364
+ paths,
365
+ parentName,
366
+ formAttrsNameInstance,
312
367
  // ================================================================================
313
368
  itemClassName: item_cls,
314
- itemStyle: { ...(parent_formItemStyle || {}), ...styleBase, ...(style || {}) },
369
+ itemStyle: {
370
+ ...(itemBorderColor && itemBorderType === 'bottom' ? { borderBottomColor: itemBorderColor } : {}),
371
+ ...(parent_formItemStyle || {}),
372
+ ...styleBase,
373
+ ...(style || {}),
374
+ },
315
375
  containerClassName: itemContainer_cls,
316
376
  itemLabelClassName: itemLabel_cls,
317
377
  itemLabelStyle: { ...(parent_formItemLabelStyle || {}), ...(labelStyle || {}) },
318
378
  itemBodyClassName: itemBody_cls,
319
- itemBodyStyle: { ...(parent_formItemBodyStyle || {}), ...(bodyStyle || {}) },
379
+ itemBodyStyle: {
380
+ ...(itemBorderColor && itemBorderType === 'body' ? { borderBottomColor: itemBorderColor } : {}),
381
+ ...(parent_formItemBodyStyle || {}),
382
+ ...(bodyStyle || {}),
383
+ },
320
384
  itemInputClassName: itemInput_cls,
321
385
  itemExtraClassName: itemExtra_cls,
322
386
  errorClassName: itemError_cls,
@@ -329,31 +393,41 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
329
393
  /**表单项值*/
330
394
  value?: any;
331
395
  /**是否校验错误*/
332
- isInvalid?: boolean;
396
+ isInvalid: boolean;
333
397
  /**边框类型*/
334
- borderedType?: FairysValtioFormLayoutContextOptions['borderedType'];
398
+ itemBorderType: FairysValtioFormLayoutContextOptions['itemBorderType'];
335
399
  /**值改变事件*/
336
- onValueChange?: (event: any) => void;
400
+ onValueChange: (event: any) => void;
337
401
  /**当前表单项占据列数*/
338
- colSpan?: number;
402
+ colSpan: number;
339
403
  /**当前表单项占据行数*/
340
- rowSpan?: number;
404
+ rowSpan: number;
341
405
  /**列数*/
342
- colCount?: number;
406
+ colCount: number;
343
407
  /**标签显示模式*/
344
- labelMode?: FairysValtioFormLayoutContextOptions['labelMode'];
408
+ labelMode: FairysValtioFormLayoutContextOptions['labelMode'];
345
409
  /**错误提示位置*/
346
- errorLayout?: FairysValtioFormLayoutContextOptions['errorLayout'];
410
+ errorLayout: FairysValtioFormLayoutContextOptions['errorLayout'];
347
411
  /**是否必填*/
348
- isRequired?: boolean;
412
+ isRequired: boolean;
349
413
  /**表单状态*/
350
- state?: T;
414
+ state: T;
351
415
  /**错误状态*/
352
- errorState?: Record<PropertyKey, string[]>;
416
+ errorState: Record<PropertyKey, string[]>;
353
417
  /**表单实例*/
354
- formInstance?: FairysValtioFormInstance<T>;
418
+ formInstance: FairysValtioFormInstance<T>;
355
419
  /**错误信息*/
356
420
  error?: string[];
421
+ /**拼接父级字段名后得到的表单项名称*/
422
+ _name?: string;
423
+ /**表单项名称*/
424
+ name?: string;
425
+ /**表单项路径*/
426
+ paths?: (string | number)[];
427
+ /**父级字段名*/
428
+ parentName?: string;
429
+ /**表单属性名实例*/
430
+ formAttrsNameInstance: FairysValtioFormParentAttrs;
357
431
  // =========================================
358
432
  /**表单项类名*/
359
433
  itemClassName: string;
@@ -380,3 +454,97 @@ export interface FairysValtioFormItemAttrsReturn<T extends MObject<T> = object>
380
454
  /**子元素*/
381
455
  children?: React.ReactNode;
382
456
  }
457
+
458
+ /**
459
+ * 没有样式的表单项属性,仅返回基础输入组件参数
460
+ *
461
+ * @example
462
+ *
463
+ *```tsx
464
+ import { Fragment } from 'react'
465
+ import { useFairysValtioFormItemAttrs, FairysValtioFormParentAttrsContext } from "@fairys/valtio-form"
466
+ import type { FairysValtioFormItemAttrsProps } from "@fairys/valtio-form"
467
+ export interface FormItemProps extends FairysValtioFormItemAttrsProps{}
468
+
469
+ export const FormItem = (props: FormItemProps) => {
470
+ const { children , formAttrsNameInstance } = useFairysValtioFormItemNoStyleAttrs(props)
471
+ return <FairysValtioFormParentAttrsContext.Provider value={formAttrsNameInstance}>
472
+ {children}
473
+ </FairysValtioFormParentAttrsContext.Provider>
474
+ }
475
+ * ```
476
+ */
477
+ export function useFairysValtioFormItemNoStyleAttrs<T extends MObject<T> = object>(
478
+ props: FairysValtioFormItemAttrsProps<T>,
479
+ ) {
480
+ const {
481
+ name,
482
+ valuePropName = 'value',
483
+ getValueFromEvent,
484
+ formatValue,
485
+ onAfterUpdate,
486
+ trigger = 'onChange',
487
+ children,
488
+ attrs = {},
489
+ isJoinParentField = true,
490
+ rules,
491
+ } = props;
492
+ const [state, errorState, formInstance] = useFairysValtioFormInstanceContextState<T>();
493
+ const {
494
+ name: _name,
495
+ paths,
496
+ parentName,
497
+ formAttrsNameInstance,
498
+ } = useFairysValtioFormAttrsName({ name, isJoinParentField });
499
+ const value = useMemo(() => get(state, paths), [state, paths]);
500
+ const error = errorState[_name];
501
+ formInstance.nameToPaths[_name] = paths;
502
+ /**挂载校验规则*/
503
+ if (Array.isArray(rules) && rules.length) {
504
+ formInstance.mountRules[_name] = rules;
505
+ }
506
+
507
+ useEffect(() => {
508
+ return () => {
509
+ formInstance.removeRules(_name);
510
+ };
511
+ }, [_name]);
512
+
513
+ const onValueChange = (event: any) => {
514
+ let value = event;
515
+ const target = event?.detail || event?.target;
516
+ if (typeof getValueFromEvent === 'function') {
517
+ value = getValueFromEvent(event, formInstance);
518
+ } else if (event && target && typeof target === 'object' && valuePropName in target) {
519
+ value = target.valuePropName;
520
+ }
521
+ if (typeof formatValue === 'function') {
522
+ value = formatValue(value, formInstance, event);
523
+ }
524
+ formInstance.updatedValueByPaths(_name, value);
525
+ if (typeof onAfterUpdate === 'function') {
526
+ onAfterUpdate(value, formInstance, event);
527
+ }
528
+ };
529
+ /**基础组件参数*/
530
+ const baseControl = {
531
+ ...attrs,
532
+ name,
533
+ [valuePropName]: value,
534
+ [trigger]: onValueChange,
535
+ };
536
+ return {
537
+ value,
538
+ error,
539
+ onValueChange,
540
+ state,
541
+ errorState,
542
+ formInstance,
543
+ _name,
544
+ name,
545
+ paths,
546
+ parentName,
547
+ formAttrsNameInstance,
548
+ children: React.isValidElement(children) ? React.cloneElement(children, { ...baseControl }) : children,
549
+ };
550
+ }