4b712de788
## Summary - Rename `effect-fc-next` to `effect-view` and update package metadata, internal symbols, imports, and repository references. - Promote the Effect 4 example to `packages/example` and move the legacy Effect 3 example to `packages/effect-fc-example`. - Add `effect-view` to the npm publishing workflow. - Update the Vite Fast Refresh plugin for `effect-view` and rename `effectViewPlugin()` to `effectView()`. - Upgrade Effect, React, TypeScript, build tooling, and related dependencies. - Refresh the documentation and homepage. ## Documentation - Add a dedicated Async guide covering: - Suspense fallbacks - Hook ordering - Memoization - Structural prop equality - Clarify synchronous and asynchronous component behavior. - Document runner scope and service requirements. - Explain stable construction of Query, Mutation, and Form instances. - Expand focused Lens and Form examples, including curried focus helpers. - Document the optional `@effect/platform-browser` dependency for window-focus query refresh. - Improve the Forms guide structure and examples. - Fix responsive homepage headline wrapping and update homepage copy. ## Notable API changes - Package rename: ```diff - effect-fc-next + effect-view --------- Co-authored-by: Julien Valverdé <julien.valverde@mailo.com> Reviewed-on: #59
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import { Callout, Flex, Spinner, Switch, TextField } from "@radix-ui/themes"
|
|
import { Array, Option, Struct } from "effect"
|
|
import { Component, Form, View } from "effect-view"
|
|
import type * as React from "react"
|
|
|
|
|
|
export declare namespace TextFieldOptionalFormInputView {
|
|
export interface Props<out P extends readonly PropertyKey[], A, ER, EW>
|
|
extends Omit<TextField.RootProps, "form" | "defaultValue">, Form.useOptionalInput.Options<string> {
|
|
readonly form: Form.Form<P, A, Option.Option<string>, ER, EW>
|
|
}
|
|
|
|
export type Signature = <P extends readonly PropertyKey[], A, ER, EW>(props: Props<P, A, ER, EW>) => React.ReactNode
|
|
}
|
|
|
|
export const TextFieldOptionalFormInputView = Component.make("TextFieldOptionalFormInputView")(function*(
|
|
props: TextFieldOptionalFormInputView.Props<readonly PropertyKey[], any, any, any>
|
|
) {
|
|
const input = yield* Form.useOptionalInput(props.form, props)
|
|
const [issues, isValidating, isCommitting] = yield* View.useAll([
|
|
props.form.issues,
|
|
props.form.isValidating,
|
|
props.form.isCommitting,
|
|
])
|
|
|
|
return (
|
|
<Flex direction="column" gap="1">
|
|
<TextField.Root
|
|
value={input.value}
|
|
onChange={e => input.setValue(e.target.value)}
|
|
disabled={!input.enabled || isCommitting}
|
|
{...Struct.omit(props, ["form", "defaultValue"])}
|
|
>
|
|
<TextField.Slot side="left">
|
|
<Switch
|
|
size="1"
|
|
checked={input.enabled}
|
|
onCheckedChange={input.setEnabled}
|
|
/>
|
|
</TextField.Slot>
|
|
|
|
{isValidating &&
|
|
<TextField.Slot side="right">
|
|
<Spinner />
|
|
</TextField.Slot>
|
|
}
|
|
|
|
{props.children}
|
|
</TextField.Root>
|
|
|
|
{Option.match(Array.head(issues), {
|
|
onSome: issue => (
|
|
<Callout.Root>
|
|
<Callout.Text>{issue.message}</Callout.Text>
|
|
</Callout.Root>
|
|
),
|
|
|
|
onNone: () => <></>,
|
|
})}
|
|
</Flex>
|
|
)
|
|
}).pipe(
|
|
Component.withSignature<TextFieldOptionalFormInputView.Signature>()
|
|
)
|