This commit is contained in:
@@ -1,24 +1,22 @@
|
||||
import { Callout, Flex, Spinner, TextField } from "@radix-ui/themes"
|
||||
import { Array, Option } from "effect"
|
||||
import { Array, Option, Struct } from "effect"
|
||||
import { Component, Form, Subscribable } from "effect-fc"
|
||||
|
||||
|
||||
export declare namespace TextFieldFormInputView {
|
||||
export interface Props
|
||||
extends TextField.RootProps, Form.useInput.Options {
|
||||
readonly field: Form.FormField<any, string>
|
||||
export interface Props extends Omit<TextField.RootProps, "form">, Form.useInput.Options {
|
||||
readonly form: Form.Form<readonly PropertyKey[], any, string>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class TextFieldFormInputView extends Component.make("TextFieldFormInputView")(function*(
|
||||
props: TextFieldFormInputView.Props
|
||||
) {
|
||||
const input = yield* Form.useInput(props.field, props)
|
||||
const input = yield* Form.useInput(props.form, props)
|
||||
const [issues, isValidating, isSubmitting] = yield* Subscribable.useSubscribables([
|
||||
props.field.issues,
|
||||
props.field.isValidating,
|
||||
props.field.isSubmitting,
|
||||
props.form.issues,
|
||||
props.form.isValidating,
|
||||
props.form.isSubmitting,
|
||||
])
|
||||
|
||||
return (
|
||||
@@ -27,7 +25,7 @@ export class TextFieldFormInputView extends Component.make("TextFieldFormInputVi
|
||||
value={input.value}
|
||||
onChange={e => input.setValue(e.target.value)}
|
||||
disabled={isSubmitting}
|
||||
{...props}
|
||||
{...Struct.omit(props, "form")}
|
||||
>
|
||||
{isValidating &&
|
||||
<TextField.Slot side="right">
|
||||
|
||||
@@ -4,21 +4,19 @@ import { Component, Form, Subscribable } from "effect-fc"
|
||||
|
||||
|
||||
export declare namespace TextFieldOptionalFormInputView {
|
||||
export interface Props
|
||||
extends Omit<TextField.RootProps, "defaultValue">, Form.useOptionalInput.Options<string> {
|
||||
readonly field: Form.FormField<any, Option.Option<string>>
|
||||
export interface Props extends Omit<TextField.RootProps, "form" | "defaultValue">, Form.useOptionalInput.Options<string> {
|
||||
readonly form: Form.Form<readonly PropertyKey[], any, Option.Option<string>>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class TextFieldOptionalFormInputView extends Component.make("TextFieldOptionalFormInputView")(function*(
|
||||
props: TextFieldOptionalFormInputView.Props
|
||||
) {
|
||||
const input = yield* Form.useOptionalInput(props.field, props)
|
||||
const input = yield* Form.useOptionalInput(props.form, props)
|
||||
const [issues, isValidating, isSubmitting] = yield* Subscribable.useSubscribables([
|
||||
props.field.issues,
|
||||
props.field.isValidating,
|
||||
props.field.isSubmitting,
|
||||
props.form.issues,
|
||||
props.form.isValidating,
|
||||
props.form.isSubmitting,
|
||||
])
|
||||
|
||||
return (
|
||||
@@ -27,7 +25,7 @@ export class TextFieldOptionalFormInputView extends Component.make("TextFieldOpt
|
||||
value={input.value}
|
||||
onChange={e => input.setValue(e.target.value)}
|
||||
disabled={!input.enabled || isSubmitting}
|
||||
{...Struct.omit(props, "defaultValue")}
|
||||
{...Struct.omit(props, "form", "defaultValue")}
|
||||
>
|
||||
<TextField.Slot side="left">
|
||||
<Switch
|
||||
|
||||
@@ -40,34 +40,42 @@ const RegisterFormSubmitSchema = Schema.Struct({
|
||||
})
|
||||
|
||||
class RegisterFormService extends Effect.Service<RegisterFormService>()("RegisterFormService", {
|
||||
scoped: Form.service({
|
||||
schema: RegisterFormSchema.pipe(
|
||||
Schema.compose(
|
||||
Schema.transformOrFail(
|
||||
Schema.typeSchema(RegisterFormSchema),
|
||||
Schema.typeSchema(RegisterFormSchema),
|
||||
{
|
||||
decode: v => Effect.andThen(Effect.sleep("500 millis"), ParseResult.succeed(v)),
|
||||
encode: ParseResult.succeed,
|
||||
},
|
||||
scoped: Effect.gen(function*() {
|
||||
const form = yield* Form.service({
|
||||
schema: RegisterFormSchema.pipe(
|
||||
Schema.compose(
|
||||
Schema.transformOrFail(
|
||||
Schema.typeSchema(RegisterFormSchema),
|
||||
Schema.typeSchema(RegisterFormSchema),
|
||||
{
|
||||
decode: v => Effect.andThen(Effect.sleep("500 millis"), ParseResult.succeed(v)),
|
||||
encode: ParseResult.succeed,
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
initialEncodedValue: { email: "", password: "", birth: Option.none() },
|
||||
f: Effect.fnUntraced(function*([value]) {
|
||||
yield* Effect.sleep("500 millis")
|
||||
return yield* Schema.decode(RegisterFormSubmitSchema)(value)
|
||||
}),
|
||||
debounce: "500 millis",
|
||||
initialEncodedValue: { email: "", password: "", birth: Option.none() },
|
||||
f: Effect.fnUntraced(function*([value]) {
|
||||
yield* Effect.sleep("500 millis")
|
||||
return yield* Schema.decode(RegisterFormSubmitSchema)(value)
|
||||
}),
|
||||
})
|
||||
|
||||
return {
|
||||
form,
|
||||
emailField: Form.focusObjectField(form, "email"),
|
||||
passwordField: Form.focusObjectField(form, "password"),
|
||||
birthField: Form.focusObjectField(form, "birth"),
|
||||
} as const
|
||||
})
|
||||
}) {}
|
||||
|
||||
class RegisterFormView extends Component.make("RegisterFormView")(function*() {
|
||||
const form = yield* RegisterFormService
|
||||
const [canSubmit, submitResult] = yield* Subscribable.useSubscribables([
|
||||
form.canSubmit,
|
||||
form.mutation.result,
|
||||
form.form.canSubmit,
|
||||
form.form.mutation.result,
|
||||
])
|
||||
|
||||
const runPromise = yield* Component.useRunPromise()
|
||||
@@ -84,12 +92,10 @@ class RegisterFormView extends Component.make("RegisterFormView")(function*() {
|
||||
<Container width="300">
|
||||
<form onSubmit={e => {
|
||||
e.preventDefault()
|
||||
void runPromise(form.submit)
|
||||
void runPromise(form.form.submit)
|
||||
}}>
|
||||
<Flex direction="column" gap="2">
|
||||
<TextFieldFormInput
|
||||
field={yield* form.field(["email"])}
|
||||
/>
|
||||
<TextFieldFormInput form={form.emailField} />
|
||||
|
||||
<TextFieldFormInput
|
||||
field={yield* form.field(["password"])}
|
||||
|
||||
Reference in New Issue
Block a user