();
// 初始化fieldProps
- currentPath && form?.setFieldProps(currentPath, fieldProps);
+ form?.setFieldProps(currentPath, fieldProps);
// 订阅更新值的函数
useEffect(() => {
@@ -100,10 +100,11 @@ export const ItemCore = (props: ItemCoreProps) => {
form.setInitialValue(currentPath, initValue);
onFieldsMounted && onFieldsMounted({ name: currentPath, value: initValue }, form?.getFieldValue());
return () => {
+ if (!currentPath) return;
// 清除该表单域的props(在设置值的前面)
- currentPath && form?.setFieldProps(currentPath, undefined);
+ form?.setFieldProps(currentPath, undefined);
// 清除初始值
- currentPath && form.setInitialValue(currentPath, undefined);
+ form?.setInitialValue(currentPath, undefined);
};
}, [JSON.stringify(currentPath)]);
diff --git a/packages/form/src/form-item.tsx b/packages/form/src/form-item.tsx
index a676d8c..957d6d8 100644
--- a/packages/form/src/form-item.tsx
+++ b/packages/form/src/form-item.tsx
@@ -2,7 +2,7 @@ import React, { useContext, CSSProperties, useMemo } from 'react';
import { SimpleFormContext } from './context';
import { useFormError } from './hooks';
import { Item, ItemProps } from './components/Item';
-import { ItemCore, ItemCoreProps } from './item-core';
+import { ItemCore, ItemCoreProps } from './core';
export type FormItemOptions = Omit
& ItemCoreProps & {
component?: React.ComponentType | React.ForwardRefExoticComponent | null;
diff --git a/packages/form/src/form.tsx b/packages/form/src/form.tsx
index 4df0281..781634b 100644
--- a/packages/form/src/form.tsx
+++ b/packages/form/src/form.tsx
@@ -31,20 +31,24 @@ export function Form(props: FormProps) {
useEffect(() => {
if (!form || !watch) return;
- Object.entries(watch)?.forEach(([key, watcher]) => {
- // 函数形式
- if (typeof watcher === 'function') {
- form?.subscribeFormValue(key, watcher);
- // 对象形式
- } else if (isObject(watcher)) {
- if (typeof watcher.handler === 'function') {
- form?.subscribeFormValue(key, watcher.handler);
+ if (typeof watch === 'function') {
+ form?.subscribeFormValue(watch);
+ } else {
+ Object.entries(watch)?.forEach(([key, watcher]) => {
+ // 函数形式
+ if (typeof watcher === 'function') {
+ form?.subscribeFormValue(key, watcher);
+ // 对象形式
+ } else if (isObject(watcher)) {
+ if (typeof watcher.handler === 'function') {
+ form?.subscribeFormValue(key, watcher.handler);
+ }
+ if (watcher.immediate) {
+ watcher.handler(form?.getFieldValue(key), form?.getLastValue(key));
+ }
}
- if (watcher.immediate) {
- watcher.handler(form?.getFieldValue(key), form?.getLastValue(key));
- }
- }
- });
+ });
+ }
return () => {
form?.unsubscribeFormValue();
};
diff --git a/packages/form/src/index.ts b/packages/form/src/index.ts
index 5b68827..a793f2e 100644
--- a/packages/form/src/index.ts
+++ b/packages/form/src/index.ts
@@ -1,10 +1,9 @@
-export * from './item-core';
+export * from './core';
export * from './form';
export * from './form-item';
export * from './store';
export * from './context';
export * from './hooks';
-export * from './components/Tooltip';
export * from './components/Item';
export * from './utils/utils';
export * from './validator';
diff --git a/packages/form/src/store.ts b/packages/form/src/store.ts
index 379e4ea..d5875e7 100644
--- a/packages/form/src/store.ts
+++ b/packages/form/src/store.ts
@@ -1,7 +1,7 @@
import { deepGet, deepSet, getValuePropName, comparePrefix } from './utils/utils';
import { deepClone } from './utils/object';
import { handleRules, isCanTrigger } from './validator';
-import { getRulesTriggers, getTriggers } from './item-core';
+import { getRulesTriggers, getTriggers } from './core';
import { isEmpty, isObject } from './utils/type';
import { FormItemProps } from './form-item';
import { PathValue } from './typings';
@@ -104,16 +104,12 @@ export class SimpleForm {
getBindProps(path?: string, newValue?: V) {
if (!path) return;
const props = this.getFieldProps(path);
- const currentValue = this.getFieldValue(path);
+ const currentValue = newValue !== undefined ? newValue : this.getFieldValue(path);
const { valueProp, valueSetter, trigger, validateTrigger, rules, nonform } = props || {};
const valuePropName = getValuePropName(valueProp) || "";
const triggers = getTriggers(trigger, validateTrigger, getRulesTriggers(rules));
const childValue = typeof valueSetter === 'function' ? valueSetter(currentValue) : (valueSetter ? undefined : currentValue);
const bindProps = { [valuePropName]: childValue } as Record;
- if (newValue !== undefined) {
- const newChildValue = typeof valueSetter === 'function' ? valueSetter(newValue) : (valueSetter ? undefined : newValue);
- bindProps[valuePropName] = newChildValue;
- }
triggers.forEach((eventName) => {
bindProps[eventName] = (...args) => {
this.bindChange(path, eventName, ...args);
@@ -123,7 +119,7 @@ export class SimpleForm {
}
// 设置表单域
- public setFieldProps(path: string, field?: V) {
+ public setFieldProps(path?: string, field?: V) {
if (!path) return;
const lastField = this.fieldPropsMap[path];
if (field === undefined) {
diff --git a/packages/form/src/utils/type.ts b/packages/form/src/utils/type.ts
index 99a1643..8902b1f 100644
--- a/packages/form/src/utils/type.ts
+++ b/packages/form/src/utils/type.ts
@@ -5,51 +5,51 @@ export function getType(obj: T) {
return Object.prototype.toString.call(obj);
}
-export function isBoolean(data: T) {
+export function isBoolean(data: T | boolean): data is boolean {
return getType(data) == '[object Boolean]';
}
-export function isNumber(data: T) {
+export function isNumber(data: T | number): data is number {
return getType(data) == '[object Number]';
}
-export function isString(data: T) {
+export function isString(data: T | string): data is string {
return getType(data) == '[object String]';
}
-export function isFunction(data: T) {
+export function isFunction(data: T | Function): data is Function {
return getType(data) == '[object Function]';
}
-export function isArray(data: T) {
+export function isArray(data: T | unknown[]): data is unknown[] {
return getType(data) == '[object Array]';
}
-export function isDate(data: T) {
+export function isDate(data: T | Date): data is Date {
return data instanceof Date;
}
-export function isRegExp(data: T) {
+export function isRegExp(data: T | RegExp): data is RegExp {
return getType(data) == '[object RegExp]';
}
-export function isUndefined(data: T) {
+export function isUndefined(data: T | undefined): data is undefined {
return getType(data) == '[object Undefined]';
}
-export function isNull(data: T) {
+export function isNull(data: T | null): data is null {
return getType(data) == '[object Null]';
}
-export function isObject(data: T) {
+export function isObject(data: T | object): data is object {
return getType(data) == '[object Object]';
}
-export function isElement(data: T) {
+export function isElement(data: T | Element): data is Element {
return data instanceof Element;
}
-export function isDom(data: T & { nodeType?: number; nodeName?: string }) {
+export function isDom(data: T & { nodeType?: number; nodeName?: string } | HTMLElement): data is HTMLElement {
if (typeof HTMLElement === 'object') {
return data instanceof HTMLElement;
} else {
@@ -57,12 +57,13 @@ export function isDom(data: T & { nodeType?: number; nodeName?: string }) {
}
}
-export function isNodeList(data: T) {
+export function isNodeList(data: T | NodeList): data is NodeList {
return getType(data) == '[object NodeList]';
}
// 判断值是否为空
-export function isEmpty(value: T) {
+type EmptyType = undefined | null | '' | [] | {};
+export function isEmpty(value: T | EmptyType): value is EmptyType {
if (value === undefined || value === null) return true;
if (Array.isArray(value)
|| typeof value === 'string'
@@ -82,13 +83,14 @@ export function isEmpty(value: T) {
if (typeof value === 'number') {
return isNaN(value);
}
+ return false;
}
-export function isArrayBuffer(data: T) {
+export function isArrayBuffer(data: T | ArrayBuffer): data is ArrayBuffer {
return getType(data) === '[object ArrayBuffer]';
}
-export function isFormData(data: T) {
+export function isFormData(data: T | FormData): data is FormData {
return (typeof FormData !== 'undefined') && (data instanceof FormData);
}
@@ -102,11 +104,11 @@ export function isArrayBufferView(data: T & { buffer?: ArrayBuffer }) {
return result;
}
-export function isFile(data: T) {
+export function isFile(data: T | File): data is File {
return getType(data) === '[object File]';
}
-export function isBlob(data: T) {
+export function isBlob(data: T | Blob): data is Blob {
return getType(data) === '[object Blob]';
}
@@ -115,24 +117,27 @@ export function isStream(data: T & { pipe?: Function }) {
}
// 是否为简单类型
-export function isBase(data: T) {
+type BaseTypes = string | number | symbol | boolean;
+export function isBase(data: T | BaseTypes): data is BaseTypes {
const type = typeof data;
return ['string', 'number', 'symbol', 'boolean']?.includes(type);
}
// 是否为数字字符串或者数字
-export const isNumberStr = (str?: T) => {
+type NumberOrStr = string | number;
+export const isNumberStr = (str?: T | NumberOrStr): str is NumberOrStr => {
if (typeof str === 'number' && !isNaN(str)) return true;
if (typeof str === 'string') {
const target = Number(str);
if (!isNaN(target) && str) return true;
}
+ return false;
};
// 是否为带data:开头的base64的字符串
-export const isBase64 = (str?: T) => {
- if (typeof str !== 'string') return;
- if (str.trim() === '') return;
+export const isBase64 = (str?: T | string): str is string => {
+ if (typeof str !== 'string') return false;
+ if (str.trim() === '') return false;
const regx = /^(data:\S+\/\S+;base64,){1}/;
return regx.test(str);
};
diff --git a/packages/form/src/utils/utils.ts b/packages/form/src/utils/utils.ts
index 5fdd741..c001dd0 100644
--- a/packages/form/src/utils/utils.ts
+++ b/packages/form/src/utils/utils.ts
@@ -1,5 +1,5 @@
import { PathValue } from "../typings";
-import { ItemCoreProps } from "../item-core";
+import { ItemCoreProps } from "../core";
import { isArray, isEmpty, isObject } from "./type";
import { deepClone } from "./object";
@@ -9,7 +9,7 @@ export function pathToArr(path?: FormPathType) {
if (path instanceof Array) return path;
if (typeof path === 'number') return [path];
const regex = /([^\.\[\]]+)|(\[\d+\])/g;
- const parts = typeof path === 'string' ? path.match(regex) : [];
+ const parts = typeof path === 'string' ? path.match(regex) as string[] : [];
return parts || [];
}
@@ -96,7 +96,7 @@ export function getValueFromEvent(...args) {
}
// 是否携带中括号
-export const isWithBracket = (code?: unknown) => {
+export const isWithBracket = (code?: T) => {
return typeof code === 'string' && /^\[\d+\]$/.test(code);
};
diff --git a/packages/form/src/validator/index.ts b/packages/form/src/validator/index.ts
index 604d405..2d40520 100644
--- a/packages/form/src/validator/index.ts
+++ b/packages/form/src/validator/index.ts
@@ -1,4 +1,4 @@
-import { ItemCoreProps } from "../item-core";
+import { ItemCoreProps } from "../core";
import { configValidator, ConfigValidatorKeys } from "./rules";
export type FormRule = {
required?: boolean;
diff --git a/packages/form/src/validator/rules.ts b/packages/form/src/validator/rules.ts
index 2da6513..554e792 100644
--- a/packages/form/src/validator/rules.ts
+++ b/packages/form/src/validator/rules.ts
@@ -52,11 +52,11 @@ const min = (ruleValue: T, value?: unknown) => {
// 导出校验方法
export const configValidator = {
- 'required': required,
- 'pattern': pattern,
- 'whitespace': whitespace,
- 'max': max,
- 'min': min
+ required,
+ pattern,
+ whitespace,
+ max,
+ min
};
export type ConfigValidator = typeof configValidator;
diff --git a/packages/render/README.md b/packages/render/README.md
index 8a00eb2..fa289fb 100644
--- a/packages/render/README.md
+++ b/packages/render/README.md
@@ -2,7 +2,7 @@
English | [中文说明](./README_CN.md)
-[![](https://img.shields.io/badge/version-4.1.26-green)](https://www.npmjs.com/package/@simpleform/render)
+[![](https://img.shields.io/badge/version-4.1.27-green)](https://www.npmjs.com/package/@simpleform/render)
> A lightweight dynamic forms engine that makes it easy to dynamically render forms.
diff --git a/packages/render/README_CN.md b/packages/render/README_CN.md
index 3e079c9..7a1365d 100644
--- a/packages/render/README_CN.md
+++ b/packages/render/README_CN.md
@@ -2,7 +2,7 @@
[English](./README.md) | 中文说明
-[![](https://img.shields.io/badge/version-4.1.26-green)](https://www.npmjs.com/package/@simpleform/render)
+[![](https://img.shields.io/badge/version-4.1.27-green)](https://www.npmjs.com/package/@simpleform/render)
> 轻量级动态表单引擎,实现动态渲染表单很简单.
diff --git a/packages/render/package.json b/packages/render/package.json
index f4b1b99..342d0ca 100644
--- a/packages/render/package.json
+++ b/packages/render/package.json
@@ -1,6 +1,6 @@
{
"name": "@simpleform/render",
- "version": "4.1.26",
+ "version": "4.1.27",
"description": "dynamic rendering core of simple form",
"author": "mezhanglei <496623925@qq.com>",
"homepage": "https://github.com/mezhanglei/simpleform#readme",
@@ -45,7 +45,7 @@
"react-router-dom": "^6.19.0"
},
"dependencies": {
- "@simpleform/form": "^2.1.14",
+ "@simpleform/form": "^2.1.15",
"classnames": "^2.3.2",
"copy-anything": "^3.0.5",
"serialize-javascript": "^6.0.2"
diff --git a/packages/render/src/children.tsx b/packages/render/src/children.tsx
index c860e9f..d76cef6 100644
--- a/packages/render/src/children.tsx
+++ b/packages/render/src/children.tsx
@@ -18,6 +18,7 @@ export default function FormChildren(props: FormChildrenProps) {
variables,
onRenderChange,
renderList,
+ components = {},
widgetList: propWidgetList,
parser = parseExpression,
form = formContext?.form,
@@ -29,6 +30,7 @@ export default function FormChildren(props: FormChildrenProps) {
parser,
formrender,
form,
+ components,
variables: curVariables,
});
diff --git a/packages/render/src/utils/ReactIs.ts b/packages/render/src/utils/ReactIs.ts
deleted file mode 100644
index 94bd929..0000000
--- a/packages/render/src/utils/ReactIs.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { isValidElementType } from "react-is";
-import { isEmpty } from "./type";
-
-// 是否为组件(不包括html标签字符串)
-export function isValidComponent(component?: unknown) {
- if (isEmpty(component) || typeof component === 'string') return false;
- return isValidElementType(component);
-};
diff --git a/packages/render/src/utils/framework.ts b/packages/render/src/utils/framework.ts
new file mode 100644
index 0000000..5cfd285
--- /dev/null
+++ b/packages/render/src/utils/framework.ts
@@ -0,0 +1,21 @@
+import React from "react";
+import { isValidElementType } from "react-is";
+import { isEmpty } from "./type";
+
+// 是否为组件(不包括html标签字符串)
+export function isValidComponent(component?: unknown) {
+ if (isEmpty(component) || typeof component === 'string') return false;
+ return isValidElementType(component);
+};
+
+export const isValidElement = (val?: T | React.ReactElement): val is React.ReactElement => {
+ return React.isValidElement(val);
+};
+
+export const createElement = (...args: Parameters): ReturnType => {
+ return React.createElement(...args);
+};
+
+export const cloneElement = (...args: Parameters