-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
244 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import { ReactNode } from "react"; | ||
import { Button, Spin } from "antd"; | ||
import { effect, watch } from "alien-deepsignals"; | ||
import { AbstractModel } from "@formula/core/model/abstract_model"; | ||
interface Props { | ||
app: ReactNode, | ||
form: AbstractModel<Record<string, any>> | ||
} | ||
|
||
export function App(props: Props) { | ||
const [state, setState] = useState(false) | ||
const [submitting, setSubmitted] = useState(false) | ||
const [model, setModel] = useState({} as any) | ||
|
||
useEffect(() => { | ||
effect(() => { | ||
setState(props.form.isUpdating.value) | ||
setSubmitted(props.form.submiting.value) | ||
}) | ||
watch(props.form.model, (model) => { | ||
setModel({ ...model }) | ||
}, { | ||
immediate: true, | ||
deep: true | ||
}); | ||
}, []) | ||
return <div> | ||
<div style={{ marginBottom: 20 }}> | ||
model: {JSON.stringify(model, null, 2)} | ||
</div> | ||
<Spin spinning={state || submitting}> | ||
{props.app} | ||
<Button style={{ width: "400px" }} type="primary" onClick={async () => { | ||
const model = await props.form.submit() | ||
alert(JSON.stringify(model, null, 2)) | ||
}}>登录</Button> | ||
</Spin> | ||
</div> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
import React from "react"; | ||
import { ReactNode } from "react"; | ||
import { createForm } from "@formula/react" | ||
import { createDecision, defineField, match } from "@formula/core"; | ||
import { z } from "zod"; | ||
import { zodResolver } from "@formula/resolvers"; | ||
import { defineRelation } from "@formula/core" | ||
import Form from "../../components/Form"; | ||
import Input from "../../components/Input"; | ||
import { App } from "./app" | ||
import InputNumber from "../../components/InputNumber"; | ||
import { Info } from "./info" | ||
interface Props { | ||
label: string | ||
type?: "Group" | "Search" | "TextArea" | "Password" | "OTP"; | ||
prefix?: ReactNode | ||
required?: boolean | ||
} | ||
interface Model { | ||
account: { | ||
username: string | ||
password: string | ||
age: number, | ||
address: string | ||
} | ||
} | ||
|
||
const boolsConfig = { | ||
isTom: (model: Model) => model.account.username === "tom", | ||
isJerry: (model: Model) => model.account.username === "jerry", | ||
is18: (model: Model) => model.account.age >= 18, | ||
isChongqing: (model: Model) => model.account.address === "重庆" | ||
} | ||
|
||
const D = createDecision(boolsConfig) | ||
|
||
const nameRelaition = defineRelation([ | ||
[ | ||
"account.age", | ||
(field, age) => { | ||
console.log(`${field.value} is ${age} years old`); | ||
} | ||
], | ||
[ | ||
["account.address", "account.age"], | ||
(field, [address, age]) => { | ||
if (address && age) { | ||
console.log(`${field.value} is ${age} years old, and he lives in ${address}`); | ||
} | ||
} | ||
], | ||
function (field) { | ||
if (field.execDecision(D.and("is18", "isTom"))) { | ||
console.log("Tom is 18 years old"); | ||
} | ||
} | ||
]) | ||
|
||
const infoRelaition = defineRelation([ | ||
[ | ||
["account.username", "account.age"], | ||
(field, [username, age]) => { | ||
if (field.value.length < 2 && username && age) { | ||
field.value = [`${username} is ${age} years old`] | ||
} | ||
} | ||
], | ||
[ | ||
["account.username", "account.address", "account.age"], | ||
(field, [username, address, age]) => { | ||
if (username && address && age ) { | ||
field.value= [ | ||
field.value[0], | ||
`${username} is ${age} years old, and he lives in ${address}` | ||
] | ||
} | ||
} | ||
], | ||
]) | ||
|
||
const username = defineField<string, Props>() | ||
.component({ | ||
id: "username", | ||
component: Input | ||
}) | ||
.props({ | ||
label: "用户名", | ||
prefix: "👤", | ||
required: true | ||
}) | ||
.relation(nameRelaition) | ||
.validator(z.string({ message: "用户名为必填项" }).min(2, "用户名长度必须在2-10").max(10, "用户名长度必须在2-10").regex(/^[a-zA-Z]+$/, { message: "用户名必须是英文" })) | ||
.build() | ||
|
||
const password = defineField<string, Props>() | ||
.component({ | ||
id: "password", | ||
component: Input, | ||
}) | ||
.props({ label: "密码", type: "Password", prefix: "🔒", required: true }) | ||
.validator( | ||
z.string({ message: "密码必须包含大小写字母、数字和特殊字符" }) | ||
.min(6, "密码长度必须在6-16").max(16, "密码长度必须在6-16") | ||
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{6,16}$/, { message: "密码必须包含大小写字母、数字和特殊字符" }) | ||
) | ||
.events({ | ||
onChange: function (value) { | ||
const res = match(this.execDecision(D.and("is18", "isTom")), | ||
[ | ||
[true, () => "Tom is 18"], | ||
[false, () => "Tom is not 18"] | ||
] | ||
) | ||
console.log(res) | ||
this.value = value | ||
} | ||
}) | ||
.build() | ||
|
||
const age = defineField<number, Props>() | ||
.component({ | ||
id: "age", | ||
component: InputNumber, | ||
hidden: D.use('isJerry') | ||
}).props({ | ||
label: "年龄", | ||
prefix: "🎂", | ||
required: true | ||
}) | ||
|
||
const address = defineField<string, Props>() | ||
.component({ | ||
id: "address", | ||
component: Input, | ||
}) | ||
.props({ | ||
label: "地址", | ||
prefix: "🏠", | ||
required: true | ||
}) | ||
.validator(z.string({ message: "地址为必填项" }).min(2, "地址长度必须在2-10").max(10, "地址长度必须在2-10")) | ||
.build() | ||
|
||
const info = defineField<any, any>().component({ | ||
id: "info", | ||
component: Info, | ||
}).actions({ | ||
setDefaultValue() { | ||
return ["请填写信息"] | ||
}, | ||
}).relation(infoRelaition).build() | ||
|
||
const useraccount = defineField<Model['account'], any>() | ||
.component({ | ||
id: "account", | ||
component: Form, | ||
}) | ||
.properties([ | ||
username, | ||
password, | ||
age, | ||
address, | ||
info | ||
]) | ||
.props({ | ||
style: { | ||
width: "400px" | ||
} | ||
}) | ||
.build() | ||
|
||
|
||
const { app, form } = createForm({ | ||
id: "boolless", | ||
defaultValidatorEngine: "zod", | ||
graph: [ | ||
useraccount | ||
], | ||
boolsConfig, | ||
resolvers: { | ||
validator: { | ||
zod: zodResolver | ||
} | ||
} | ||
}) | ||
export default function () { | ||
return <App app={app} form={form} /> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import React from "react" | ||
import { Space, Typography } from 'antd'; | ||
export function Info({ | ||
value | ||
}: { value: string[] }) { | ||
return <Space direction="vertical"> | ||
{ | ||
value.map((v, i) => <Typography.Text key={i}>{v}</Typography.Text>) | ||
} | ||
</Space> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters