diff --git a/packages/effect-fc/src/Form.ts b/packages/effect-fc/src/Form.ts index b91ff37..360598f 100644 --- a/packages/effect-fc/src/Form.ts +++ b/packages/effect-fc/src/Form.ts @@ -105,7 +105,7 @@ export const make: { export const run = ( self: Form -): Effect.Effect => Stream.runForEach( +): Effect.Effect => Stream.runForEach( self.encodedValueRef.changes.pipe( Option.isSome(self.debounce) ? Stream.debounce(self.debounce.value) : identity ), @@ -125,21 +125,22 @@ export const run = ( Effect.andThen(SubscriptionRef.set(self.errorRef, Option.none())), Effect.as(Option.some(v)), ), - onFailure: c => Option.match( - Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"), - { - onSome: e => Effect.as(SubscriptionRef.set(self.errorRef, Option.some(e)), Option.none()), - onNone: () => Effect.succeed(Option.none()), - }, + onFailure: c => Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError").pipe( + Option.match({ + onSome: e => SubscriptionRef.set(self.errorRef, Option.some(e)), + onNone: () => Effect.void, + }), + Effect.as(Option.none()), ), }), Effect.uninterruptible, )), + Effect.scoped, + Effect.andThen(value => Option.isSome(value) && self.autosubmit - ? + ? Effect.asVoid(Effect.forkScoped(submit(self))) : Effect.void ), - Effect.scoped, Effect.forkScoped, ) ), @@ -175,7 +176,7 @@ export namespace service { export const service = ( options: service.Options -): Effect.Effect, never, Scope.Scope | R> => Effect.tap( +): Effect.Effect, never, Scope.Scope | R | SR> => Effect.tap( make(options), form => Effect.forkScoped(run(form)), ) diff --git a/packages/example/src/routes/dev/async-rendering.tsx b/packages/example/src/routes/dev/async-rendering.tsx index e5a23e8..5bd2e6a 100644 --- a/packages/example/src/routes/dev/async-rendering.tsx +++ b/packages/example/src/routes/dev/async-rendering.tsx @@ -2,7 +2,7 @@ import { Flex, Text, TextField } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" import { GetRandomValues, makeUuid4 } from "@typed/id" import { Effect } from "effect" -import { Async, Component, Hooks, Memoized } from "effect-fc" +import { Async, Component, Memoized } from "effect-fc" import * as React from "react" import { runtime } from "@/runtime" @@ -69,7 +69,7 @@ class AsyncComponent extends Component.makeUntraced("AsyncComponent")(function*( class MemoizedAsyncComponent extends Memoized.memoized(AsyncComponent) {} class SubComponent extends Component.makeUntraced("SubComponent")(function*() { - const [state] = React.useState(yield* Hooks.useOnce(() => Effect.provide(makeUuid4, GetRandomValues.CryptoRandom))) + const [state] = React.useState(yield* Component.useOnMount(() => Effect.provide(makeUuid4, GetRandomValues.CryptoRandom))) return {state} }) {} diff --git a/packages/example/src/routes/form.tsx b/packages/example/src/routes/form.tsx index 722e2d8..e45047a 100644 --- a/packages/example/src/routes/form.tsx +++ b/packages/example/src/routes/form.tsx @@ -1,7 +1,7 @@ import { Button, Container, Flex } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" import { Console, Effect, Option, ParseResult, Schema } from "effect" -import { Component, Form, Hooks } from "effect-fc" +import { Component, Form, Subscribable } from "effect-fc" import { TextFieldFormInput } from "@/lib/form/TextFieldFormInput" import { DateTimeUtcFromZonedInput } from "@/lib/schema" import { runtime } from "@/runtime" @@ -50,7 +50,7 @@ class RegisterForm extends Effect.Service()("RegisterForm", { class RegisterFormView extends Component.makeUntraced("RegisterFormView")(function*() { const form = yield* RegisterForm const submit = yield* Form.useSubmit(form) - const [canSubmit] = yield* Hooks.useSubscribables(form.canSubmitSubscribable) + const [canSubmit] = yield* Subscribable.useSubscribables(form.canSubmitSubscribable) const TextFieldFormInputFC = yield* TextFieldFormInput @@ -87,7 +87,7 @@ class RegisterFormView extends Component.makeUntraced("RegisterFormView")(functi const RegisterPage = Component.makeUntraced("RegisterPage")(function*() { const RegisterFormViewFC = yield* Effect.provide( RegisterFormView, - yield* Hooks.useContext(RegisterForm.Default, { finalizerExecutionMode: "fork" }), + yield* Component.useContext(RegisterForm.Default, { finalizerExecutionMode: "fork" }), ) return diff --git a/packages/example/src/routes/index.tsx b/packages/example/src/routes/index.tsx index 8da0367..d87902d 100644 --- a/packages/example/src/routes/index.tsx +++ b/packages/example/src/routes/index.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from "@tanstack/react-router" import { Effect } from "effect" -import { Component, Hooks } from "effect-fc" +import { Component } from "effect-fc" import { runtime } from "@/runtime" import { Todos } from "@/todo/Todos" import { TodosState } from "@/todo/TodosState.service" @@ -11,7 +11,7 @@ const TodosStateLive = TodosState.Default("todos") const Index = Component.makeUntraced("Index")(function*() { const TodosFC = yield* Effect.provide( Todos, - yield* Hooks.useContext(TodosStateLive, { finalizerExecutionMode: "fork" }), + yield* Component.useContext(TodosStateLive, { finalizerExecutionMode: "fork" }), ) return diff --git a/packages/example/src/todo/Todo.tsx b/packages/example/src/todo/Todo.tsx index f01304b..4c3e386 100644 --- a/packages/example/src/todo/Todo.tsx +++ b/packages/example/src/todo/Todo.tsx @@ -1,7 +1,7 @@ import { Box, Button, Flex, IconButton } from "@radix-ui/themes" import { GetRandomValues, makeUuid4 } from "@typed/id" -import { Chunk, DateTime, Effect, Match, Option, Ref, Runtime, Schema, Stream, SubscriptionRef } from "effect" -import { Component, Form, Hooks, Memoized, Subscribable, SubscriptionSubRef } from "effect-fc" +import { Chunk, Effect, Match, Option, Ref, Runtime, Schema, Stream } from "effect" +import { Component, Form, Subscribable } from "effect-fc" import { FaArrowDown, FaArrowUp } from "react-icons/fa" import { FaDeleteLeft } from "react-icons/fa6" import * as Domain from "@/domain" @@ -61,6 +61,7 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr Match.exhaustive, ) }, + autosubmit: props._tag === "edit", }) return [ @@ -71,7 +72,7 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr ] as const }), [props._tag, props._tag === "edit" ? props.id : undefined]) - const [index, size] = yield* Hooks.useSubscribables(indexRef, state.sizeSubscribable) + const [index, size] = yield* Subscribable.useSubscribables(indexRef, state.sizeSubscribable) const submit = yield* Form.useSubmit(form) const TextFieldFormInputFC = yield* TextFieldFormInput @@ -80,9 +81,7 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr - + {props._tag === "new" && - } @@ -131,6 +123,4 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr } ) -}).pipe( - Memoized.memoized -) {} +}) {}