This commit is contained in:
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
|
}
|
||||||
1
bun.lock
1
bun.lock
@@ -38,6 +38,7 @@
|
|||||||
"mobx": "^6.13.7",
|
"mobx": "^6.13.7",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@effect/language-service": "^0.23.4",
|
||||||
"@eslint/js": "^9.26.0",
|
"@eslint/js": "^9.26.0",
|
||||||
"@tanstack/react-router": "^1.120.3",
|
"@tanstack/react-router": "^1.120.3",
|
||||||
"@tanstack/react-router-devtools": "^1.120.3",
|
"@tanstack/react-router-devtools": "^1.120.3",
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class SubscriptionSubRefImpl<in out A, in out B> extends Effectable.Class<A> imp
|
|||||||
readonly setter: (parentValue: B, value: A) => B,
|
readonly setter: (parentValue: B, value: A) => B,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
this.get = Effect.map(Ref.get(this.parent), this.getter)
|
this.get = Effect.map(this.parent, this.getter)
|
||||||
}
|
}
|
||||||
|
|
||||||
commit() {
|
commit() {
|
||||||
@@ -86,9 +86,11 @@ class SubscriptionSubRefImpl<in out A, in out B> extends Effectable.Class<A> imp
|
|||||||
|
|
||||||
export const makeFromGetSet = <A, B>(
|
export const makeFromGetSet = <A, B>(
|
||||||
parent: SubscriptionRef.SubscriptionRef<B>,
|
parent: SubscriptionRef.SubscriptionRef<B>,
|
||||||
getter: (parentValue: B) => A,
|
options: {
|
||||||
setter: (parentValue: B, value: A) => B,
|
readonly get: (parentValue: B) => A
|
||||||
): SubscriptionSubRef<A, B> => new SubscriptionSubRefImpl(parent, getter, setter)
|
readonly set: (parentValue: B, value: A) => B
|
||||||
|
},
|
||||||
|
): SubscriptionSubRef<A, B> => new SubscriptionSubRefImpl(parent, options.get, options.set)
|
||||||
|
|
||||||
export const makeFromPath = <B, const P extends PropertyPath.Paths<B>>(
|
export const makeFromPath = <B, const P extends PropertyPath.Paths<B>>(
|
||||||
parent: SubscriptionRef.SubscriptionRef<B>,
|
parent: SubscriptionRef.SubscriptionRef<B>,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@effect/language-service": "^0.23.4",
|
||||||
"@eslint/js": "^9.26.0",
|
"@eslint/js": "^9.26.0",
|
||||||
"@tanstack/react-router": "^1.120.3",
|
"@tanstack/react-router": "^1.120.3",
|
||||||
"@tanstack/react-router-devtools": "^1.120.3",
|
"@tanstack/react-router-devtools": "^1.120.3",
|
||||||
|
|||||||
48
packages/example/src/todo/TodosState.ts
Normal file
48
packages/example/src/todo/TodosState.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { Todo } from "@/domain"
|
||||||
|
import { KeyValueStore } from "@effect/platform"
|
||||||
|
import { Chunk, Console, Effect, Option, Schema, Stream, SubscriptionRef } from "effect"
|
||||||
|
import { SubscriptionSubRef } from "effect-fc/types"
|
||||||
|
|
||||||
|
|
||||||
|
export class TodosState extends Effect.Service<TodosState>()("TodosState", {
|
||||||
|
effect: Effect.fnUntraced(function*(key: string) {
|
||||||
|
const kv = yield* KeyValueStore.KeyValueStore
|
||||||
|
|
||||||
|
const readFromLocalStorage = Console.log("Reading todos from local storage...").pipe(
|
||||||
|
Effect.andThen(kv.get(key)),
|
||||||
|
Effect.flatMap(Option.match({
|
||||||
|
onSome: Schema.decode(
|
||||||
|
Schema.parseJson(Schema.Chunk(Todo.TodoFromJson))
|
||||||
|
),
|
||||||
|
onNone: () => Effect.succeed(Chunk.empty()),
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
|
const saveToLocalStorage = (todos: Chunk.Chunk<Todo.Todo>) => Effect.andThen(
|
||||||
|
Console.log("Saving todos to local storage..."),
|
||||||
|
Chunk.isNonEmpty(todos)
|
||||||
|
? Effect.flatMap(
|
||||||
|
Schema.encode(
|
||||||
|
Schema.parseJson(Schema.Chunk(Todo.TodoFromJson))
|
||||||
|
)(todos),
|
||||||
|
v => kv.set(key, v),
|
||||||
|
)
|
||||||
|
: kv.remove(key)
|
||||||
|
)
|
||||||
|
|
||||||
|
const ref = yield* SubscriptionRef.make(yield* readFromLocalStorage)
|
||||||
|
|
||||||
|
const makeSubRef = (index: number) => SubscriptionSubRef.makeFromGetSet(ref, {
|
||||||
|
get: parent => Chunk.unsafeGet(parent, index),
|
||||||
|
set: (parent, v) => Chunk.replace(parent, index, v),
|
||||||
|
})
|
||||||
|
|
||||||
|
yield* Effect.forkScoped(ref.changes.pipe(
|
||||||
|
Stream.debounce("500 millis"),
|
||||||
|
Stream.runForEach(saveToLocalStorage),
|
||||||
|
))
|
||||||
|
yield* Effect.addFinalizer(() => Effect.flatMap(ref, saveToLocalStorage))
|
||||||
|
|
||||||
|
return { ref, makeSubRef } as const
|
||||||
|
})
|
||||||
|
}) {}
|
||||||
@@ -24,7 +24,13 @@
|
|||||||
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
},
|
||||||
|
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "@effect/language-service"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user