0.1.4 #5

Merged
Thilawyn merged 67 commits from next into master 2025-10-02 18:18:23 +02:00
10 changed files with 37 additions and 33 deletions
Showing only changes of commit 8c1fed7800 - Show all commits

View File

@@ -1,4 +1,4 @@
import { Context, Effect, Effectable, ExecutionStrategy, Function, Predicate, Runtime, Scope, String, Tracer, type Types, type Utils } from "effect"
import { Context, Effect, Effectable, ExecutionStrategy, Function, Predicate, Runtime, Scope, Tracer, type Types, type Utils } from "effect"
import * as React from "react"
import { Hooks } from "./hooks/index.js"
import * as Memo from "./Memo.js"
@@ -331,13 +331,9 @@ export const make: (
) => make.Gen & make.NonGen)
) = (spanNameOrBody: Function | string, ...pipeables: any[]): any => {
if (typeof spanNameOrBody !== "string") {
const displayName = displayNameFromBody(spanNameOrBody)
return Object.setPrototypeOf(
Object.assign(function() {}, defaultOptions, {
body: displayName
? Effect.fn(displayName)(spanNameOrBody as any, ...pipeables as [])
: Effect.fn(spanNameOrBody as any, ...pipeables),
displayName,
body: Effect.fn(spanNameOrBody as any, ...pipeables),
}),
ComponentProto,
)
@@ -347,25 +343,33 @@ export const make: (
return (body: any, ...pipeables: any[]) => Object.setPrototypeOf(
Object.assign(function() {}, defaultOptions, {
body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []),
displayName: displayNameFromBody(body) ?? spanNameOrBody,
displayName: spanNameOrBody,
}),
ComponentProto,
)
}
}
export const makeUntraced: make.Gen & make.NonGen = (
body: Function,
...pipeables: any[]
) => Object.setPrototypeOf(
export const makeUntraced: (
& make.Gen
& make.NonGen
& ((name: string) => make.Gen & make.NonGen)
) = (spanNameOrBody: Function | string, ...pipeables: any[]): any => (
typeof spanNameOrBody !== "string"
? Object.setPrototypeOf(
Object.assign(function() {}, defaultOptions, {
body: Effect.fnUntraced(body as any, ...pipeables as []),
displayName: displayNameFromBody(body),
body: Effect.fnUntraced(spanNameOrBody as any, ...pipeables as []),
}),
ComponentProto,
)
const displayNameFromBody = (body: Function) => !String.isEmpty(body.name) ? body.name : undefined
: (body: any, ...pipeables: any[]) => Object.setPrototypeOf(
Object.assign(function() {}, defaultOptions, {
body: Effect.fnUntraced(body, ...pipeables as []),
displayName: spanNameOrBody,
}),
ComponentProto,
)
)
export const withOptions: {
<T extends Component<any, any, any, any>>(

View File

@@ -15,7 +15,7 @@ export const TextAreaInput = <A, R>(options: {
React.JSX.Element,
ParseResult.ParseError,
R
> => Component.makeUntraced(function* TextFieldInput(props) {
> => Component.makeUntraced("TextFieldInput")(function* TextFieldInput(props) {
const input = yield* useInput({ ...options, ...props })
const issue = React.useMemo(() => input.error.pipe(
Option.map(ParseResult.ArrayFormatter.formatErrorSync),

View File

@@ -18,7 +18,7 @@ export const TextFieldInput = <A, R, O extends boolean = false>(options: {
readonly optional?: O
readonly schema: Schema.Schema<A, string, R>
readonly equivalence?: Equivalence.Equivalence<A>
}) => Component.makeUntraced(function* TextFieldInput(props: O extends true
}) => Component.makeUntraced("TextFieldInput")(function* TextFieldInput(props: O extends true
? TextFieldOptionalInputProps<A, R>
: TextFieldInputProps<A, R>
) {

View File

@@ -51,7 +51,7 @@ const RouteComponent = Component.makeUntraced(function* AsyncRendering() {
// )
class AsyncComponent extends Component.makeUntraced(function* AsyncComponent() {
class AsyncComponent extends Component.makeUntraced("AsyncComponent")(function*() {
const SubComponentFC = yield* SubComponent
yield* Effect.sleep("500 millis") // Async operation
@@ -69,7 +69,7 @@ class AsyncComponent extends Component.makeUntraced(function* AsyncComponent() {
) {}
class MemoizedAsyncComponent extends Memo.memo(AsyncComponent) {}
class SubComponent extends Component.makeUntraced(function* SubComponent() {
class SubComponent extends Component.makeUntraced("SubComponent")(function*() {
const [state] = React.useState(yield* Hooks.useOnce(() => Effect.provide(makeUuid4, GetRandomValues.CryptoRandom)))
return <Text>{state}</Text>
}) {}

View File

@@ -4,7 +4,7 @@ import { Container } from "@radix-ui/themes"
import { createFileRoute } from "@tanstack/react-router"
import { Schema, SubscriptionRef } from "effect"
import { Component, Memo } from "effect-fc"
import { useInput, useOnce, useRefState } from "effect-fc/hooks"
import { useOnce } from "effect-fc/hooks"
const IntFromString = Schema.NumberFromString.pipe(Schema.int())
@@ -12,18 +12,18 @@ const IntFromString = Schema.NumberFromString.pipe(Schema.int())
const IntTextFieldInput = TextFieldInput({ schema: IntFromString })
const StringTextFieldInput = TextFieldInput({ schema: Schema.String })
const Input = Component.makeUntraced(function* Input() {
const Input = Component.makeUntraced("Input")(function*() {
const IntTextFieldInputFC = yield* IntTextFieldInput
const StringTextFieldInputFC = yield* StringTextFieldInput
const intRef1 = yield* useOnce(() => SubscriptionRef.make(0))
const intRef2 = yield* useOnce(() => SubscriptionRef.make(0))
// const intRef2 = yield* useOnce(() => SubscriptionRef.make(0))
const stringRef = yield* useOnce(() => SubscriptionRef.make(""))
// yield* useFork(() => Stream.runForEach(intRef1.changes, Console.log), [intRef1])
const input2 = yield* useInput({ schema: IntFromString, ref: intRef2 })
// const input2 = yield* useInput({ schema: IntFromString, ref: intRef2 })
const [str, setStr] = yield* useRefState(stringRef)
// const [str, setStr] = yield* useRefState(stringRef)
return (
<Container>

View File

@@ -7,7 +7,7 @@ import { Component, Memo } from "effect-fc"
import * as React from "react"
const RouteComponent = Component.makeUntraced(function* RouteComponent() {
const RouteComponent = Component.makeUntraced("RouteComponent")(function*() {
const [value, setValue] = React.useState("")
return (
@@ -25,7 +25,7 @@ const RouteComponent = Component.makeUntraced(function* RouteComponent() {
Component.withRuntime(runtime.context)
)
class SubComponent extends Component.makeUntraced(function* SubComponent() {
class SubComponent extends Component.makeUntraced("SubComponent")(function*() {
const id = yield* makeUuid4.pipe(Effect.provide(GetRandomValues.CryptoRandom))
return <Text>{id}</Text>
}) {}

View File

@@ -28,7 +28,7 @@ class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
})
}) {}
class RegisterPage extends Component.makeUntraced(function* RegisterPage() {
class RegisterPage extends Component.makeUntraced("RegisterPage")(function*() {
const form = yield* RegisterForm
const emailInput = yield* Form.useInput(form, ["email"], { debounce: "200 millis" })
const passwordInput = yield* Form.useInput(form, ["password"], { debounce: "200 millis" })

View File

@@ -9,7 +9,7 @@ import { useContext } from "effect-fc/hooks"
const TodosStateLive = TodosState.Default("todos")
const Index = Component.makeUntraced(function* Index() {
const Index = Component.makeUntraced("Index")(function*() {
const context = yield* useContext(TodosStateLive, { finalizerExecutionMode: "fork" })
const TodosFC = yield* Effect.provide(Todos, context)

View File

@@ -31,7 +31,7 @@ export type TodoProps = (
| { readonly _tag: "edit", readonly id: string }
)
export class Todo extends Component.makeUntraced(function* Todo(props: TodoProps) {
export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoProps) {
const runtime = yield* Effect.runtime()
const state = yield* TodosState

View File

@@ -6,7 +6,7 @@ import { Todo } from "./Todo"
import { TodosState } from "./TodosState.service"
export class Todos extends Component.makeUntraced(function* Todos() {
export class Todos extends Component.makeUntraced("Todos")(function*() {
const state = yield* TodosState
const [todos] = yield* useSubscribe(state.ref)