0.1.4 #5
@@ -21,7 +21,7 @@ extends Pipeable.Pipeable {
|
|||||||
): Subscribable.Subscribable<readonly ParseResult.ArrayFormatterIssue[]>
|
): Subscribable.Subscribable<readonly ParseResult.ArrayFormatterIssue[]>
|
||||||
|
|
||||||
useInput<P extends PropertyPath.Paths<I>>(
|
useInput<P extends PropertyPath.Paths<I>>(
|
||||||
path: P
|
options: Form.useInput.Options<I, P>
|
||||||
): Effect.Effect<
|
): Effect.Effect<
|
||||||
Form.useInput.Result<PropertyPath.ValueFromPath<I, P>>,
|
Form.useInput.Result<PropertyPath.ValueFromPath<I, P>>,
|
||||||
ParseResult.ParseError | NoSuchElementException,
|
ParseResult.ParseError | NoSuchElementException,
|
||||||
@@ -31,9 +31,14 @@ extends Pipeable.Pipeable {
|
|||||||
|
|
||||||
export namespace Form {
|
export namespace Form {
|
||||||
export namespace useInput {
|
export namespace useInput {
|
||||||
export interface Result<I> {
|
export interface Options<I, P extends PropertyPath.Paths<I>> {
|
||||||
readonly value: I
|
readonly path: P
|
||||||
readonly setValue: React.Dispatch<React.SetStateAction<I>>
|
readonly defaultValue?: PropertyPath.ValueFromPath<NoInfer<I>, NoInfer<P>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Result<T> {
|
||||||
|
readonly value: T
|
||||||
|
readonly setValue: React.Dispatch<React.SetStateAction<T>>
|
||||||
readonly issues: readonly ParseResult.ArrayFormatterIssue[]
|
readonly issues: readonly ParseResult.ArrayFormatterIssue[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,15 +91,24 @@ extends Pipeable.Class() implements Form<A, I, R> {
|
|||||||
}, [this.latestValueRef, ...path])
|
}, [this.latestValueRef, ...path])
|
||||||
}
|
}
|
||||||
|
|
||||||
useInput<P extends PropertyPath.Paths<I>>(path: P) {
|
useInput<P extends PropertyPath.Paths<I>>(
|
||||||
|
options: Form.useInput.Options<I, P>
|
||||||
|
) {
|
||||||
const self = this
|
const self = this
|
||||||
return Effect.gen(function*() {
|
return Effect.gen(function*() {
|
||||||
const internalValueRef = yield* Hooks.useMemo(() => self.latestValueRef.pipe(
|
const internalValueRef = yield* Hooks.useMemo(() => self.latestValueRef.pipe(
|
||||||
Effect.andThen(Schema.encode(self.schema)),
|
Effect.andThen(flow(
|
||||||
Effect.andThen(PropertyPath.get(path)),
|
Schema.encode(self.schema),
|
||||||
|
Effect.andThen(PropertyPath.get(options.path)),
|
||||||
|
Effect.catchTag("ParseError", e => options.defaultValue !== undefined && options.defaultValue !== null
|
||||||
|
? Effect.succeed(options.defaultValue)
|
||||||
|
: Effect.fail(e)
|
||||||
|
),
|
||||||
|
)),
|
||||||
Effect.andThen(SubscriptionRef.make<PropertyPath.ValueFromPath<I, P>>),
|
Effect.andThen(SubscriptionRef.make<PropertyPath.ValueFromPath<I, P>>),
|
||||||
), [self.latestValueRef, ...path])
|
), [self.latestValueRef, ...options.path])
|
||||||
const issuesSubscribable = self.useFieldIssuesSubscribable(path)
|
|
||||||
|
const issuesSubscribable = self.useFieldIssuesSubscribable(options.path)
|
||||||
|
|
||||||
const [value, setValue] = yield* Hooks.useRefState(internalValueRef)
|
const [value, setValue] = yield* Hooks.useRefState(internalValueRef)
|
||||||
const [issues] = yield* Hooks.useSubscribe(issuesSubscribable)
|
const [issues] = yield* Hooks.useSubscribe(issuesSubscribable)
|
||||||
@@ -107,7 +121,7 @@ extends Pipeable.Class() implements Form<A, I, R> {
|
|||||||
),
|
),
|
||||||
internalValue => self.latestValueRef.pipe(
|
internalValue => self.latestValueRef.pipe(
|
||||||
Effect.andThen(Schema.encode(self.schema)),
|
Effect.andThen(Schema.encode(self.schema)),
|
||||||
Effect.andThen(PropertyPath.immutableSet(path, internalValue)),
|
Effect.andThen(PropertyPath.immutableSet(options.path, internalValue)),
|
||||||
Effect.andThen(flow(
|
Effect.andThen(flow(
|
||||||
Schema.decode(self.schema),
|
Schema.decode(self.schema),
|
||||||
Effect.andThen(v => SubscriptionRef.set(self.latestValueRef, v)),
|
Effect.andThen(v => SubscriptionRef.set(self.latestValueRef, v)),
|
||||||
@@ -115,7 +129,7 @@ extends Pipeable.Class() implements Form<A, I, R> {
|
|||||||
Effect.catchTag("ParseError", e => SubscriptionRef.set(self.errorRef, Option.some(e)))
|
Effect.catchTag("ParseError", e => SubscriptionRef.set(self.errorRef, Option.some(e)))
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
), [internalValueRef, self.latestValueRef, self.schema, self.errorRef, ...path])
|
), [internalValueRef, self.latestValueRef, self.schema, self.errorRef, ...options.path])
|
||||||
|
|
||||||
return { value, setValue, issues }
|
return { value, setValue, issues }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,22 +6,22 @@ import { Component, Form } from "effect-fc"
|
|||||||
import { useContext, useFork } from "effect-fc/hooks"
|
import { useContext, useFork } from "effect-fc/hooks"
|
||||||
|
|
||||||
|
|
||||||
const LoginFormSchema = Schema.Struct({
|
const RegisterFormSchema = Schema.Struct({
|
||||||
email: Schema.String,
|
email: Schema.String,
|
||||||
password: Schema.String.pipe(Schema.minLength(3)),
|
password: Schema.String.pipe(Schema.minLength(3)),
|
||||||
})
|
})
|
||||||
|
|
||||||
class LoginForm extends Effect.Service<LoginForm>()("LoginForm", {
|
class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
|
||||||
scoped: Form.make({
|
scoped: Form.make({
|
||||||
schema: LoginFormSchema,
|
schema: RegisterFormSchema,
|
||||||
initialValue: { email: "", password: "xxx" },
|
initialValue: { email: "", password: "" },
|
||||||
})
|
})
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
class LoginFormComponent extends Component.makeUntraced(function* LoginFormComponent() {
|
class RegisterPage extends Component.makeUntraced(function* RegisterPage() {
|
||||||
const form = yield* LoginForm
|
const form = yield* RegisterForm
|
||||||
const emailInput = yield* form.useInput(["email"])
|
const emailInput = yield* form.useInput({ path: ["email"], defaultValue: "" })
|
||||||
const passwordInput = yield* form.useInput(["password"])
|
const passwordInput = yield* form.useInput({ path: ["password"], defaultValue: "" })
|
||||||
|
|
||||||
yield* useFork(() => Stream.runForEach(form.latestValueSubscribable.changes, Console.log), [])
|
yield* useFork(() => Stream.runForEach(form.latestValueSubscribable.changes, Console.log), [])
|
||||||
|
|
||||||
@@ -63,15 +63,15 @@ class LoginFormComponent extends Component.makeUntraced(function* LoginFormCompo
|
|||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
|
|
||||||
const FormRoute = Component.makeUntraced(function* FormRoute() {
|
const RegisterRoute = Component.makeUntraced(function* RegisterRoute() {
|
||||||
const context = yield* useContext(LoginForm.Default)
|
const context = yield* useContext(RegisterForm.Default)
|
||||||
const LoginFormComponentFC = yield* Effect.provide(LoginFormComponent, context)
|
const RegisterRouteFC = yield* Effect.provide(RegisterPage, context)
|
||||||
|
|
||||||
return <LoginFormComponentFC />
|
return <RegisterRouteFC />
|
||||||
}).pipe(
|
}).pipe(
|
||||||
Component.withRuntime(runtime.context)
|
Component.withRuntime(runtime.context)
|
||||||
)
|
)
|
||||||
|
|
||||||
export const Route = createFileRoute("/form")({
|
export const Route = createFileRoute("/form")({
|
||||||
component: FormRoute
|
component: RegisterRoute
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user