Skip to content

Commit

Permalink
feat: unitedSchema JSON add requiredMode configuration (#150)
Browse files Browse the repository at this point in the history
requiredMode:default, drip-form delete empty fieldData.
requiredMode:empty, configure minLength、minItems keywords to verify required.
  • Loading branch information
mengshang918 committed Mar 9, 2022
1 parent 4636dcf commit 7e717ef
Show file tree
Hide file tree
Showing 23 changed files with 199 additions and 108 deletions.
1 change: 1 addition & 0 deletions packages/ajv/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function registerAjv(options?: Options): Ajv {
// 添加drip-form官方忽略关键字(添加customFormat是为了node校验支持旧版的语法)
ajv.addVocabulary([
'validateTime',
'requiredMode',
'$container',
'customFormat',
// v1需要过滤该字段
Expand Down
80 changes: 45 additions & 35 deletions packages/drip-form/src/DripForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @Author: jiangxiaowei
* @Date: 2020-05-14 16:54:32
* @Last Modified by: jiangxiaowei
* @Last Modified time: 2022-03-02 21:28:18
* @Last Modified time: 2022-03-09 17:33:29
*/
import React, {
forwardRef,
Expand All @@ -21,7 +21,13 @@ import validate from '../validate'
import formDataReducer, { FormDataContext } from '../reducers'
import renderCoreFn from '../render'
import { typeCheck, parseUnitedSchema, randomString } from '@jdfed/utils'
import { useValidate, useSchema, useGetKey, usePrevious } from '@jdfed/hooks'
import {
useValidate,
useSchema,
useGetKey,
usePrevious,
RequiredModeContext,
} from '@jdfed/hooks'
import containerMap from '../container'
import Footer from './Footer'
import type { DripFormRenderProps, DripFormRefType, ControlFuc } from './type'
Expand Down Expand Up @@ -443,39 +449,43 @@ const DripForm = forwardRef<DripFormRefType, DripFormRenderProps>(
const globalTheme: Theme = theme

return (
<FormDataContext.Provider value={globalFormDataStoreKey}>
<div className={'drip-form-root'}>
{renderCoreFn({
hasDefault,
uiComponents,
dataSchema,
uiSchema,
errors,
formData,
onQuery,
onValidate,
dispatch,
customComponents,
containerMap,
getKey,
get,
containerHoc,
arrayKey,
isRoot: true,
})}
<Footer
uiSchema={uiSchema}
uiComponents={uiComponents}
onSubmit={onSubmit}
submit={submit}
submitReturn={submitReturn}
onCancel={onCancel}
globalTheme={globalTheme}
initFormData={initArgs.formData}
dispatch={dispatch}
/>
</div>
</FormDataContext.Provider>
<RequiredModeContext.Provider
value={dataSchema?.requiredMode || 'default'}
>
<FormDataContext.Provider value={globalFormDataStoreKey}>
<div className={'drip-form-root'}>
{renderCoreFn({
hasDefault,
uiComponents,
dataSchema,
uiSchema,
errors,
formData,
onQuery,
onValidate,
dispatch,
customComponents,
containerMap,
getKey,
get,
containerHoc,
arrayKey,
isRoot: true,
})}
<Footer
uiSchema={uiSchema}
uiComponents={uiComponents}
onSubmit={onSubmit}
submit={submit}
submitReturn={submitReturn}
onCancel={onCancel}
globalTheme={globalTheme}
initFormData={initArgs.formData}
dispatch={dispatch}
/>
</div>
</FormDataContext.Provider>
</RequiredModeContext.Provider>
)
}
)
Expand Down
8 changes: 6 additions & 2 deletions packages/drip-form/src/reducers/addField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @Author: jiangxiaowei
* @Date: 2021-10-26 15:29:06
* @Last Modified by: jiangxiaowei
* @Last Modified time: 2022-01-26 17:19:18
* @Last Modified time: 2022-03-09 17:06:58
*/
import { produce } from 'immer'
import { setDeepProp, parseUnitedSchema } from '@jdfed/utils'
Expand Down Expand Up @@ -73,7 +73,11 @@ const addField = ({
const { dataSchema: addParentDataSchema, uiSchema: addParentUiSchema } =
get(addParentPath)
// 待添加表单的dataSchema、uiSchema
const { dataSchema, uiSchema } = parseUnitedSchema(unitedSchema)
const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
dataSchema: { validateTime, requiredMode, ...dataSchema },
uiSchema,
} = parseUnitedSchema(unitedSchema)
// 待添加表单 父级元素类型 默认对象类型
let addParentType = 'object'
if (addParentUiSchema.type === 'array') {
Expand Down
4 changes: 2 additions & 2 deletions packages/drip-form/src/reducers/deleteField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* @Author: jiangxiaowei
* @Date: 2021-10-26 19:25:56
* @Last Modified by: jiangxiaowei
* @Last Modified time: 2022-01-26 17:16:23
* @Last Modified time: 2022-03-09 14:10:37
*/
import { produce, original } from 'immer'
import { deleteDeepProp, parseUnitedSchema, setDeepProp } from '@jdfed/utils'
import { deleteDeepProp, setDeepProp } from '@jdfed/utils'
import type { State } from '@jdfed/utils'

const deleteField = ({
Expand Down
53 changes: 45 additions & 8 deletions packages/generator/src/components/RightSideBar/Check/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @Author: jiangxiaowei
* @Date: 2021-08-16 11:32:22
* @Last Modified by: jiangxiaowei
* @Last Modified time: 2022-01-20 19:51:07
* @Last Modified time: 2022-03-09 17:36:37
*/
import React, { useMemo, memo, useCallback } from 'react'
import {
Expand All @@ -18,7 +18,7 @@ import commonSchema from '../../../fields/common/checkConfig/Common'
import typeMap from './type'
import { formItemMap } from '@generator/fields'
import useRightSidebar from '../HeadlessComponents'
import type { Map } from '@jdfed/utils'
import type { Map, UnitedSchema } from '@jdfed/utils'

const CheckConfig = (): JSX.Element => {
const {
Expand Down Expand Up @@ -154,7 +154,7 @@ const CheckConfig = (): JSX.Element => {
])

// 校验配置schema
const unitedSchema = useMemo(() => {
const unitedSchema = useMemo<UnitedSchema>(() => {
return {
validateTime: 'change',
theme: 'antd',
Expand All @@ -163,7 +163,7 @@ const CheckConfig = (): JSX.Element => {
{
fieldKey: 'validateTime',
type: 'string',
title: '检验时机',
title: '校验时机',
default: 'change',
ui: {
type: 'select',
Expand All @@ -173,6 +173,40 @@ const CheckConfig = (): JSX.Element => {
],
},
},
{
fieldKey: 'requiredMode',
type: 'string',
title: '必填校验模式',
default: 'default',
ui: {
type: 'radio',
description: {
type: 'text',
title: '必填校验模式详细查看文档:',
},
options: [
{
label: 'default',
description: {
title:
// eslint-disable-next-line quotes
"{a:'',b:[],c:0,d:null},以上a、b、c、d字段均不会报必填错误",
trigger: 'hover',
},
value: 'default',
},
{
label: 'empty',
description: {
// eslint-disable-next-line quotes
title: `{a:'',b:[],c:0,d:null},以上c字段不会报必填错误,a、b、d在用户配置最小长度、最少输入多少项后会报必填错误`,
trigger: 'hover',
},
value: 'empty',
},
],
},
},
]
: [
{
Expand Down Expand Up @@ -313,8 +347,8 @@ const CheckConfig = (): JSX.Element => {
Object.entries(dataSchema).map(([key, value]) => {
// TODO @jiangxiaowei 针对嵌套做适配
// TODO @jiangxiaowei 支持自定义转换
if (key === 'validateTime') {
setDeepProp(['validateTime'], formData, value)
if (['validateTime', 'requiredMode'].includes(key)) {
setDeepProp(key.split('.'), formData, value)
} else if (key !== 'errorMessage') {
setDeepProp(
[businessKeywords.has(key) ? 'business' : 'common', key],
Expand All @@ -339,9 +373,12 @@ const CheckConfig = (): JSX.Element => {
({ changeKey, get }) => {
// 变化的表单数据
const data = get(changeKey).data
if (!selectedFieldKey && changeKey === 'validateTime') {
if (
!selectedFieldKey &&
['validateTime', 'requiredMode'].includes(changeKey)
) {
generatorContext.current?.merge('', 'dataSchema', {
validateTime: data,
[changeKey]: data,
})
}
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { CopyOutlined } from '@ant-design/icons'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { usePrevious } from '@jdfed/hooks'
import type { SetType } from '@jdfed/hooks'
import type { Map } from '@jdfed/utils'
import type { Map, UnitedSchema } from '@jdfed/utils'

const PropertyConfig = () => {
const {
Expand Down Expand Up @@ -357,7 +357,7 @@ const PropertyConfig = () => {
/**
* 不同表单项生成不同的联合schema
*/
const unitedSchema = useMemo(() => {
const unitedSchema = useMemo<UnitedSchema>(() => {
return {
validateTime: 'change',
theme: 'antd',
Expand Down
6 changes: 5 additions & 1 deletion packages/hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @Author: jiangxiaowei
* @Date: 2020-05-30 13:34:38
* @Last Modified by: jiangxiaowei
* @Last Modified time: 2022-01-17 17:59:43
* @Last Modified time: 2022-03-09 17:10:17
*/
import type { Set, Merge, SetType, DeleteField, AddField } from './useSchema'
import type { Get, GetKey } from '@jdfed/utils'
Expand All @@ -22,6 +22,10 @@ export { default as useSchema } from './useSchema'
export { default as useGetKey } from './useGetKey'
export { default as useContainerStyle } from './useContainerStyle'
export { default as useTitle } from './useTitle'
export {
default as useRequiredModeContext,
RequiredModeContext,
} from './useRequiredModeContext'
export type {
Get,
Set,
Expand Down
38 changes: 26 additions & 12 deletions packages/hooks/src/useField.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { produce } from 'immer'
/*
* Field表单onChange生成 hooks
* 该hooks会自动根据
Expand All @@ -8,7 +7,9 @@ import { produce } from 'immer'
* @Last Modified time: yyyy-05-dd 15:10:43
*/
import moment, { Moment } from 'moment'
import { produce } from 'immer'
import useEventCallback from './useEventCallback'
import useRequiredModeContext from './useRequiredModeContext'
import { useDebounceFn } from 'ahooks'
import { isEmpty, typeCheck } from '@jdfed/utils'
import type { GetKey, Action } from '@jdfed/utils'
Expand Down Expand Up @@ -269,6 +270,7 @@ const useField = (
},
dispatch: Dispatch<Action>
): UseFieldR => {
const requiredMode = useRequiredModeContext()
// onChange 回调 debounce
const { run } = useDebounceFn(
(val, dispatch) => {
Expand Down Expand Up @@ -373,22 +375,34 @@ const useField = (
})
}
/**
* 删除formData中相应表单字段(fix:表单为空之后必填校验失效)
* 删除dataSchema中相应default(fix: text默认值后续删除不自动添加)
* 数组容器中子项为空不删除
*/
if (
(Object.prototype.hasOwnProperty.call(options, 'isDelete')
? options.isDelete
: isEmpty(value)) &&
(options.isDelete || isEmpty(value)) &&
getKey(fieldKey, 'dataSchema').split('.').pop() !== 'items'
) {
dispatch({
type: 'setData',
action: {
deleteKeys: fieldKey,
},
})
// 使用JSON Schema规范的required关键字校验必填
if (requiredMode === 'default') {
// 删除formData中相应表单字段(fix:表单为空之后必填校验失效)
dispatch({
type: 'setData',
action: {
deleteKeys: fieldKey,
},
})
} else {
// 通过minLength、minItems控制必填
dispatch({
type: 'setData',
action: {
set: {
[fieldKey]: value,
},
},
})
}

// 删除dataSchema中相应default(fix: text默认值后续删除不自动添加)
dispatch({
type: 'setValidate',
action: {
Expand Down
20 changes: 20 additions & 0 deletions packages/hooks/src/useRequiredModeContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* @Author: jiangxiaowei
* @Date: 2022-03-08 17:48:49
* @Last Modified by: jiangxiaowei
* @Last Modified time: 2022-03-09 17:10:13
*/

import { createContext, useContext } from 'react'

// 必填校验模式 default:必填同JSON schema reuqired关键字校验模式(会清空当前表单项) empty: 使用@jdfed/utils isEmpty判断(不会清空当前表单项)
type RequiredMode = 'default' | 'empty'
export const RequiredModeContext = createContext<RequiredMode>('default')

// 返回上一次的value值
const useRequiredModeContext = (): RequiredMode => {
const requiredMode = useContext(RequiredModeContext)
return requiredMode
}

export default useRequiredModeContext

0 comments on commit 7e717ef

Please sign in to comment.