@@ -1,6 +1,7 @@
|
||||
# React + TypeScript + Vite
|
||||
# Effect FC Example
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
Example application for the legacy `effect-fc` package, built with React,
|
||||
TypeScript, and Vite.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
<title>Effect FC Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
This library is in early development. While it is (almost) feature complete and mostly usable, expect bugs and quirks. Things are still being ironed out, so ideas and criticisms are more than welcome.
|
||||
|
||||
Documentation is currently being written. In the meantime, you can take a look at the `packages/example` directory.
|
||||
Documentation is currently being written. In the meantime, you can take a look at the `packages/effect-fc-example` directory.
|
||||
|
||||
## Peer dependencies
|
||||
- `effect` 3.19+
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"url": "git+https://github.com/Thiladev/effect-fc.git"
|
||||
"url": "git+https://github.com/Thiladev/effect-view.git"
|
||||
},
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"url": "git+https://github.com/Thiladev/effect-fc.git"
|
||||
"url": "git+https://github.com/Thiladev/effect-view.git"
|
||||
},
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as React from "react"
|
||||
import * as Component from "./Component.js"
|
||||
|
||||
|
||||
export const AsyncTypeId: unique symbol = Symbol.for("@effect-fc/Async/Async")
|
||||
export const AsyncTypeId: unique symbol = Symbol.for("@effect-view/Async/Async")
|
||||
export type AsyncTypeId = typeof AsyncTypeId
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as React from "react"
|
||||
import * as ScopeRegistry from "./ScopeRegistry.js"
|
||||
|
||||
|
||||
export const ComponentTypeId: unique symbol = Symbol.for("@effect-fc/Component/Component")
|
||||
export const ComponentTypeId: unique symbol = Symbol.for("@effect-view/Component/Component")
|
||||
export type ComponentTypeId = typeof ComponentTypeId
|
||||
|
||||
/**
|
||||
@@ -416,9 +416,9 @@ export declare namespace make {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Effect-FC Component using the same overloads and pipeline composition style as `Effect.fn`.
|
||||
* Creates an Effect View Component using the same overloads and pipeline composition style as `Effect.fn`.
|
||||
*
|
||||
* This is the **recommended** approach for defining Effect-FC components. It provides comprehensive
|
||||
* This is the **recommended** approach for defining Effect View components. It provides comprehensive
|
||||
* support for multiple component definition patterns:
|
||||
*
|
||||
* - **Generator syntax** (yield* style): Most ergonomic and readable approach for sequential operations
|
||||
@@ -491,7 +491,7 @@ export const make: (
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Effect-FC Component without automatic distributed tracing.
|
||||
* Creates an Effect View Component without automatic distributed tracing.
|
||||
*
|
||||
* This function provides the same API surface as `make`, but does not create automatic tracing spans.
|
||||
* It follows the exact same overload structure as `Effect.fnUntraced`.
|
||||
@@ -608,19 +608,19 @@ export const withOptions: {
|
||||
))
|
||||
|
||||
/**
|
||||
* Wraps an Effect-FC Component and converts it into a standard React function component,
|
||||
* serving as an **entrypoint** into an Effect-FC component hierarchy.
|
||||
* Wraps an Effect View Component and converts it into a standard React function component,
|
||||
* serving as an **entrypoint** into an Effect View component hierarchy.
|
||||
*
|
||||
* This is how Effect-FC components are integrated with the broader React ecosystem,
|
||||
* This is how Effect View components are integrated with the broader React ecosystem,
|
||||
* particularly when:
|
||||
* - Using client-side routers (TanStack Router, React Router, etc.)
|
||||
* - Implementing lazy-loaded or code-split routes
|
||||
* - Connecting to third-party libraries expecting standard React components
|
||||
* - Creating component boundaries between Effect-FC and non-Effect-FC code
|
||||
* - Creating component boundaries between Effect View and non-Effect View code
|
||||
*
|
||||
* The Effect runtime is obtained from the provided React Context.
|
||||
*
|
||||
* @param self - The Effect-FC Component to be rendered as a standard React component
|
||||
* @param self - The Effect View Component to be rendered as a standard React component
|
||||
* @param context - React Context providing the Effect Runtime for this component tree.
|
||||
* Create this using the `ReactRuntime` module.
|
||||
*
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as Lens from "./Lens.js"
|
||||
import * as View from "./View.js"
|
||||
|
||||
|
||||
export const FormTypeId: unique symbol = Symbol.for("@effect-fc/Form/Form")
|
||||
export const FormTypeId: unique symbol = Symbol.for("@effect-view/Form/Form")
|
||||
export type FormTypeId = typeof FormTypeId
|
||||
|
||||
export interface Form<out P extends readonly PropertyKey[], out A, in out I = A, out ER = never, out EW = never>
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as Lens from "./Lens.js"
|
||||
import * as View from "./View.js"
|
||||
|
||||
|
||||
export const LensFormTypeId: unique symbol = Symbol.for("@effect-fc/Form/LensForm")
|
||||
export const LensFormTypeId: unique symbol = Symbol.for("@effect-view/Form/LensForm")
|
||||
export type LensFormTypeId = typeof LensFormTypeId
|
||||
|
||||
export interface LensForm<in out A, in out I = A, in out RD = never, in out RE = never, out TER = never, out TEW = never, in out TRR = never, in out TRW = never>
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as React from "react"
|
||||
import type * as Component from "./Component.js"
|
||||
|
||||
|
||||
export const MemoizedTypeId: unique symbol = Symbol.for("@effect-fc/Memoized/Memoized")
|
||||
export const MemoizedTypeId: unique symbol = Symbol.for("@effect-view/Memoized/Memoized")
|
||||
export type MemoizedTypeId = typeof MemoizedTypeId
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as Lens from "./Lens.js"
|
||||
import * as View from "./View.js"
|
||||
|
||||
|
||||
export const MutationTypeId: unique symbol = Symbol.for("@effect-fc/Mutation/Mutation")
|
||||
export const MutationTypeId: unique symbol = Symbol.for("@effect-view/Mutation/Mutation")
|
||||
export type MutationTypeId = typeof MutationTypeId
|
||||
|
||||
export interface Mutation<in out K, out A, out E = never, in out R = never>
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as Mutation from "./Mutation.js"
|
||||
import * as View from "./View.js"
|
||||
|
||||
|
||||
export const MutationFormTypeId: unique symbol = Symbol.for("@effect-fc/Form/MutationForm")
|
||||
export const MutationFormTypeId: unique symbol = Symbol.for("@effect-view/Form/MutationForm")
|
||||
export type MutationFormTypeId = typeof MutationFormTypeId
|
||||
|
||||
export interface MutationForm<in out A, in out I = A, in out RD = never, in out RE = never, out MA = void, out ME = never, in out MR = never>
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as QueryClient from "./QueryClient.js"
|
||||
import * as View from "./View.js"
|
||||
|
||||
|
||||
export const QueryTypeId: unique symbol = Symbol.for("@effect-fc/Query/Query")
|
||||
export const QueryTypeId: unique symbol = Symbol.for("@effect-view/Query/Query")
|
||||
export type QueryTypeId = typeof QueryTypeId
|
||||
|
||||
export interface Query<in out K, out A, out E = never, in out R = never>
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as Lens from "./Lens.js"
|
||||
import type * as View from "./View.js"
|
||||
|
||||
|
||||
export const QueryClientServiceTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientService")
|
||||
export const QueryClientServiceTypeId: unique symbol = Symbol.for("@effect-view/QueryClient/QueryClientService")
|
||||
export type QueryClientServiceTypeId = typeof QueryClientServiceTypeId
|
||||
|
||||
export interface QueryClientService extends Pipeable.Pipeable {
|
||||
@@ -27,7 +27,7 @@ export interface QueryClientService extends Pipeable.Pipeable {
|
||||
}
|
||||
|
||||
export class QueryClient extends Context.Service<QueryClient, QueryClientService>()(
|
||||
"@effect-fc/QueryClient/QueryClient"
|
||||
"@effect-view/QueryClient/QueryClient"
|
||||
) {}
|
||||
|
||||
export class QueryClientServiceImpl
|
||||
@@ -129,7 +129,7 @@ export const service = (
|
||||
export const layer = (options?: service.Options) => Layer.effect(QueryClient, service(options))
|
||||
|
||||
|
||||
export const QueryClientCacheKeyTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientCacheKey")
|
||||
export const QueryClientCacheKeyTypeId: unique symbol = Symbol.for("@effect-view/QueryClient/QueryClientCacheKey")
|
||||
export type QueryClientCacheKeyTypeId = typeof QueryClientCacheKeyTypeId
|
||||
|
||||
export class QueryClientCacheKey
|
||||
@@ -155,7 +155,7 @@ implements Pipeable.Pipeable, Equal.Equal {
|
||||
export const isQueryClientCacheKey = (u: unknown): u is QueryClientCacheKey => Predicate.hasProperty(u, QueryClientCacheKeyTypeId)
|
||||
|
||||
|
||||
export const QueryClientCacheEntryTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientCacheEntry")
|
||||
export const QueryClientCacheEntryTypeId: unique symbol = Symbol.for("@effect-view/QueryClient/QueryClientCacheEntry")
|
||||
export type QueryClientCacheEntryTypeId = typeof QueryClientCacheEntryTypeId
|
||||
|
||||
export class QueryClientCacheEntry
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as Component from "./Component.js"
|
||||
import * as ScopeRegistry from "./ScopeRegistry.js"
|
||||
|
||||
|
||||
export const ReactRuntimeTypeId: unique symbol = Symbol.for("@effect-fc/ReactRuntime/ReactRuntime")
|
||||
export const ReactRuntimeTypeId: unique symbol = Symbol.for("@effect-view/ReactRuntime/ReactRuntime")
|
||||
export type ReactRuntimeTypeId = typeof ReactRuntimeTypeId
|
||||
|
||||
export interface ReactRuntime<R, ER> {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Effect FC Next Example
|
||||
# Effect View Example
|
||||
|
||||
Minimal React example for `effect-fc-next`, Effect V4, and `effect-lens@2`.
|
||||
Minimal React example for `effect-view`, Effect V4, and `effect-lens@2`.
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
```
|
||||
|
||||
The counter demonstrates a V4 `SubscriptionRef` exposed as an Effect Lens and
|
||||
rendered through an Effect-FC component.
|
||||
rendered through an Effect View component.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
<title>Effect View Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"@effect/platform-browser": "4.0.0-beta.98",
|
||||
"@radix-ui/themes": "^3.3.0",
|
||||
"effect": "4.0.0-beta.98",
|
||||
"effect-fc-next": "workspace:*",
|
||||
"effect-view": "workspace:*",
|
||||
"react-icons": "^5.6.0"
|
||||
},
|
||||
"overrides": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Callout, Flex, Spinner, TextField } from "@radix-ui/themes"
|
||||
import { Array, Option, Struct } from "effect"
|
||||
import { Component, Form, View } from "effect-fc-next"
|
||||
import { Component, Form, View } from "effect-view"
|
||||
import type * as React from "react"
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Callout, Flex, Spinner, Switch, TextField } from "@radix-ui/themes"
|
||||
import { Array, Option, Struct } from "effect"
|
||||
import { Component, Form, View } from "effect-fc-next"
|
||||
import { Component, Form, View } from "effect-view"
|
||||
import type * as React from "react"
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createRouter, RouterProvider } from "@tanstack/react-router"
|
||||
import { ReactRuntime } from "effect-fc-next"
|
||||
import { ReactRuntime } from "effect-view"
|
||||
import { StrictMode } from "react"
|
||||
import { createRoot } from "react-dom/client"
|
||||
import { routeTree } from "./routeTree.gen"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Container, Flex, Heading, Slider, Text, TextField } from "@radix-ui/themes"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { Console, Effect } from "effect"
|
||||
import { Async, Component, Memoized } from "effect-fc-next"
|
||||
import { Async, Component, Memoized } from "effect-view"
|
||||
import * as React from "react"
|
||||
import { runtime } from "@/runtime"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button, Container, Flex, Text } from "@radix-ui/themes"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { Console, Effect, Schema } from "effect"
|
||||
import { Component, Form, MutationForm, View } from "effect-fc-next"
|
||||
import { Component, Form, MutationForm, View } from "effect-view"
|
||||
import { TextFieldFormInputView } from "@/lib/form/TextFieldFormInputView"
|
||||
import { runtime } from "@/runtime"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button, Container, Flex, Text, TextField } from "@radix-ui/themes"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { Effect, SubscriptionRef } from "effect"
|
||||
import { Component, Lens, View } from "effect-fc-next"
|
||||
import { Component, Lens, View } from "effect-view"
|
||||
import { runtime } from "@/runtime"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Container, Flex } from "@radix-ui/themes"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { Console, Context, Effect, Layer, Schema, Stream, SubscriptionRef } from "effect"
|
||||
import { Component, Form, Lens, LensForm } from "effect-fc-next"
|
||||
import { Component, Form, Lens, LensForm } from "effect-view"
|
||||
import { TextFieldFormInputView } from "@/lib/form/TextFieldFormInputView"
|
||||
import { runtime } from "@/runtime"
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { createFileRoute } from "@tanstack/react-router"
|
||||
import { Effect, Schema, SubscriptionRef } from "effect"
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
import { AsyncResult } from "effect/unstable/reactivity"
|
||||
import { Component, Lens, Mutation, Query, View } from "effect-fc-next"
|
||||
import { Component, Lens, Mutation, Query, View } from "effect-view"
|
||||
import { runtime } from "@/runtime"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser"
|
||||
import { DateTime, Layer } from "effect"
|
||||
import { FetchHttpClient } from "effect/unstable/http"
|
||||
import { QueryClient, ReactRuntime } from "effect-fc-next"
|
||||
import { QueryClient, ReactRuntime } from "effect-view"
|
||||
|
||||
|
||||
export const layer = Layer.empty.pipe(
|
||||
|
||||
@@ -16,13 +16,13 @@ export default defineConfig({
|
||||
```
|
||||
|
||||
The plugin recognizes `Component.make` and `Component.makeUntraced`
|
||||
definitions imported from `effect-fc-next`. The legacy `effect-fc` package is
|
||||
not supported. `effect-fc-next` owns the bundler-neutral refresh cell protocol;
|
||||
definitions imported from `effect-view`. The legacy `effect-fc` package is
|
||||
not supported. `effect-view` owns the bundler-neutral refresh cell protocol;
|
||||
this package is the Vite adapter that retains those cells in HMR data. The
|
||||
plugin assigns stable development IDs and self-accepts successfully
|
||||
instrumented modules.
|
||||
|
||||
The adapter-facing protocol is exported from `effect-fc-next/Refreshable`.
|
||||
The adapter-facing protocol is exported from `effect-view/Refreshable`.
|
||||
|
||||
Renaming or removing an instrumented View invalidates the module upward instead
|
||||
of leaving a stale mounted descriptor.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"url": "git+https://github.com/Thiladev/effect-fc.git"
|
||||
"url": "git+https://github.com/Thiladev/effect-view.git"
|
||||
},
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
@@ -36,12 +36,12 @@
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"effect-fc-next": "workspace:*",
|
||||
"effect-view": "workspace:*",
|
||||
"vite": "^8.0.16",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"effect-fc-next": "0.1.0-beta.0",
|
||||
"effect-view": "^0.1.0",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ const refreshIdentifier = "__effectViewRefresh"
|
||||
const acceptIdentifier = "__effectViewAccept"
|
||||
|
||||
const isSupportedPackage = (source: string): boolean =>
|
||||
source === "effect-fc-next"
|
||||
|| source === "effect-fc-next/Component"
|
||||
source === "effect-view"
|
||||
|| source === "effect-view/Component"
|
||||
|
||||
const collectImports = (
|
||||
sourceFile: ts.SourceFile,
|
||||
|
||||
@@ -36,7 +36,7 @@ const transform = (
|
||||
describe("effectViewPlugin", () => {
|
||||
it("wraps a const Effect View descriptor", async () => {
|
||||
const result = await transform(`
|
||||
import { Component } from "effect-fc-next"
|
||||
import { Component } from "effect-view"
|
||||
import * as React from "react"
|
||||
|
||||
export const CounterView = Component.make("CounterView")(function*() {
|
||||
@@ -53,7 +53,7 @@ export const CounterView = Component.make("CounterView")(function*() {
|
||||
|
||||
it("registers a pipeline before withContext", async () => {
|
||||
const result = await transform(`
|
||||
import { Component } from "effect-fc-next"
|
||||
import { Component } from "effect-view"
|
||||
|
||||
const Page = Component.make("Page")(function*() {
|
||||
return <main />
|
||||
@@ -69,7 +69,7 @@ const Page = Component.make("Page")(function*() {
|
||||
|
||||
it("wraps a class's complete trait pipeline", async () => {
|
||||
const result = await transform(`
|
||||
import { Async, Component, Memoized } from "effect-fc-next"
|
||||
import { Async, Component, Memoized } from "effect-view"
|
||||
|
||||
class PostView extends Component.make("PostView")(function*() {
|
||||
const value = yield* Component.useOnMount(load)
|
||||
@@ -88,7 +88,7 @@ class PostView extends Component.make("PostView")(function*() {
|
||||
it("supports aliased Component imports and refresh reset", async () => {
|
||||
const result = await transform(`
|
||||
// @refresh reset
|
||||
import { Component as View } from "effect-fc-next"
|
||||
import { Component as View } from "effect-view"
|
||||
|
||||
const Probe = View.makeUntraced(function*() {
|
||||
return null
|
||||
@@ -113,7 +113,7 @@ export function View() {
|
||||
const id = path.join(process.cwd(), "src/Removed.tsx")
|
||||
|
||||
await runTransform(plugin, `
|
||||
import { Component } from "effect-fc-next"
|
||||
import { Component } from "effect-view"
|
||||
export const Probe = Component.makeUntraced(function*() {
|
||||
return null
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type * as Component from "effect-fc-next/Component"
|
||||
import * as Refreshable from "effect-fc-next/Refreshable"
|
||||
import type * as Component from "effect-view/Component"
|
||||
import * as Refreshable from "effect-view/Refreshable"
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
import { accept, register } from "./runtime.js"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type * as Component from "effect-fc-next/Component"
|
||||
import * as Refreshable from "effect-fc-next/Refreshable"
|
||||
import type * as Component from "effect-view/Component"
|
||||
import * as Refreshable from "effect-view/Refreshable"
|
||||
|
||||
export interface HotContext {
|
||||
readonly data: Record<string, unknown>
|
||||
|
||||
Reference in New Issue
Block a user