Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/breezy-baboons-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect-atom/atom-vue": patch
---

align Vue `useAtomSet` to the React version
12 changes: 11 additions & 1 deletion docs/atom-vue/index.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,17 @@ Added in v1.0.0
**Signature**

```ts
export declare const useAtomSet: <R, W>(atom: () => Atom.Writable<R, W>) => (_: W) => void
export declare const useAtomSet: <R, W, Mode extends "value" | "promise" | "promiseExit" = never>(
atom: () => Atom.Writable<R, W>,
options?: { readonly mode?: ([R] extends [Result.Result<any, any>] ? Mode : "value") | undefined }
) => "promise" extends Mode
? (value: W, options?: { readonly signal?: AbortSignal | undefined } | undefined) => Promise<Result.Result.Success<R>>
: "promiseExit" extends Mode
? (
value: W,
options?: { readonly signal?: AbortSignal | undefined } | undefined
) => Promise<Exit.Exit<Result.Result.Success<R>, Result.Result.Failure<R>>>
: (value: W | ((value: R) => W)) => void
```

Added in v1.0.0
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
"test": "vitest",
"coverage": "vitest --coverage",
"check": "tsc -b tsconfig.json",
"indexgen": "pnpm -r exec build-utils prepare-v2",
"docgen": "pnpm -r exec docgen && pnpm docgen-cp",
"packages": "pnpm -r --filter !*sample*",
"indexgen": "pnpm packages exec build-utils prepare-v2",
"docgen": "pnpm packages exec docgen && pnpm docgen-cp",
"docgen-cp": "node scripts/docs-cp.js"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/atom-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@types/react": "^19.1.15",
"@types/react-dom": "^19.1.9",
"@types/scheduler": "^0.26.0",
"effect": "^3.18.0",
"effect": "^3.18.4",
"jsdom": "^27.0.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/atom-vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"license": "MIT",
"sideEffects": [],
"devDependencies": {
"effect": "^3.18.0",
"effect": "^3.18.4",
"vue": "^3.5.22"
},
"peerDependencies": {
Expand Down
98 changes: 93 additions & 5 deletions packages/atom-vue/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
import type * as Atom from "@effect-atom/atom/Atom"
import type * as AtomRef from "@effect-atom/atom/AtomRef"
import * as Registry from "@effect-atom/atom/Registry"
import type * as Result from "@effect-atom/atom/Result"
import * as Cause from "effect/Cause"
import * as Effect from "effect/Effect"
import * as Exit from "effect/Exit"
import { globalValue } from "effect/GlobalValue"
import type { InjectionKey, Ref } from "vue"
import type { ComputedRef, InjectionKey, Ref } from "vue"
import { computed, inject, ref, watchEffect } from "vue"

/**
Expand Down Expand Up @@ -83,9 +87,23 @@ const useAtomValueRef = <A extends Atom.Atom<any>>(atom: () => A) => {
* @since 1.0.0
* @category composables
*/
export const useAtom = <R, W>(atom: () => Atom.Writable<R, W>): readonly [Readonly<Ref<R>>, (_: W) => void] => {
export const useAtom = <R, W, Mode extends "value" | "promise" | "promiseExit" = never>(
atom: () => Atom.Writable<R, W>,
options?: {
readonly mode?: ([R] extends [Result.Result<any, any>] ? Mode : "value") | undefined
}
): readonly [
Readonly<Ref<R>>,
write: "promise" extends Mode ? (
(value: W) => Promise<Result.Result.Success<R>>
) :
"promiseExit" extends Mode ? (
(value: W) => Promise<Exit.Exit<Result.Result.Success<R>, Result.Result.Failure<R>>>
) :
((value: W | ((value: R) => W)) => void)
] => {
const [value, atomRef, registry] = useAtomValueRef(atom)
return [value as Readonly<Ref<R>>, (_) => registry.set(atomRef.value, _)]
return [value as Readonly<Ref<R>>, setAtom(registry, atomRef, options)]
}

/**
Expand All @@ -94,17 +112,87 @@ export const useAtom = <R, W>(atom: () => Atom.Writable<R, W>): readonly [Readon
*/
export const useAtomValue = <A>(atom: () => Atom.Atom<A>): Readonly<Ref<A>> => useAtomValueRef(atom)[0]

const flattenExit = <A, E>(exit: Exit.Exit<A, E>): A => {
if (Exit.isSuccess(exit)) return exit.value
throw Cause.squash(exit.cause)
}

function setAtom<R, W, Mode extends "value" | "promise" | "promiseExit" = never>(
registry: Registry.Registry,
atomRef: ComputedRef<Atom.Writable<R, W>>,
options?: {
readonly mode?: ([R] extends [Result.Result<any, any>] ? Mode : "value") | undefined
}
): "promise" extends Mode ? (
(
value: W,
options?: {
readonly signal?: AbortSignal | undefined
} | undefined
) => Promise<Result.Result.Success<R>>
) :
"promiseExit" extends Mode ? (
(
value: W,
options?: {
readonly signal?: AbortSignal | undefined
} | undefined
) => Promise<Exit.Exit<Result.Result.Success<R>, Result.Result.Failure<R>>>
) :
((value: W | ((value: R) => W)) => void)
{
if (options?.mode === "promise" || options?.mode === "promiseExit") {
return ((value: W, opts?: any) => {
registry.set(atomRef.value, value)
const promise = Effect.runPromiseExit(
Registry.getResult(registry, atomRef.value as Atom.Atom<Result.Result<any, any>>, { suspendOnWaiting: true }),
opts
)
return options!.mode === "promise" ? promise.then(flattenExit) : promise
}) as any
}
return ((value: W | ((value: R) => W)) => {
registry.set(atomRef.value, typeof value === "function" ? (value as any)(registry.get(atomRef.value)) : value)
}) as any
}

/**
* @since 1.0.0
* @category composables
*/
export const useAtomSet = <R, W>(atom: () => Atom.Writable<R, W>): (_: W) => void => {
export const useAtomSet = <
R,
W,
Mode extends "value" | "promise" | "promiseExit" = never
>(
atom: () => Atom.Writable<R, W>,
options?: {
readonly mode?: ([R] extends [Result.Result<any, any>] ? Mode : "value") | undefined
}
): "promise" extends Mode ? (
(
value: W,
options?: {
readonly signal?: AbortSignal | undefined
} | undefined
) => Promise<Result.Result.Success<R>>
) :
"promiseExit" extends Mode ? (
(
value: W,
options?: {
readonly signal?: AbortSignal | undefined
} | undefined
) => Promise<Exit.Exit<Result.Result.Success<R>, Result.Result.Failure<R>>>
) :
((value: W | ((value: R) => W)) => void) =>
{
const registry = injectRegistry()
const atomRef = computed(atom)
watchEffect((onCleanup) => {
onCleanup(registry.mount(atomRef.value))
})
return (_) => registry.set(atomRef.value, _)
return setAtom(registry, atomRef, options)
}

/**
Expand Down
8 changes: 4 additions & 4 deletions packages/atom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
"sideEffects": [],
"devDependencies": {
"@effect/experimental": "^0.56.0",
"@effect/platform": "^0.92.0",
"@effect/platform": "^0.92.1",
"@effect/rpc": "^0.71.0",
"effect": "^3.18.0"
"effect": "^3.18.4"
},
"peerDependencies": {
"@effect/experimental": "^0.56.0",
"@effect/platform": "^0.92.0",
"@effect/platform": "^0.92.1",
"@effect/rpc": "^0.71.0",
"effect": "^3.18.0"
"effect": "^3.18.4"
}
}
Loading