@reffuse/extension-query 0.1.5 #16

Merged
Thilawyn merged 347 commits from next into master 2025-06-01 05:28:47 +02:00
4 changed files with 31 additions and 34 deletions
Showing only changes of commit 861e462ebd - Show all commits

View File

@@ -1,6 +1,5 @@
import { ThSchema } from "@thilawyn/thilaschema" import { ThSchema } from "@thilawyn/thilaschema"
import { GetRandomValues, makeUuid4 } from "@typed/id" import { Schema } from "effect"
import { Effect, Schema } from "effect"
export class Todo extends Schema.Class<Todo>("Todo")({ export class Todo extends Schema.Class<Todo>("Todo")({
@@ -18,9 +17,4 @@ export const TodoFromJsonStruct = Schema.Struct({
ThSchema.assertEncodedJsonifiable ThSchema.assertEncodedJsonifiable
) )
export const TodoFromJson = TodoFromJsonStruct.pipe(Schema.compose(Todo)) export const TodoFromJson = Schema.compose(TodoFromJsonStruct, Todo)
export const generateUniqueID = makeUuid4.pipe(
Effect.provide(GetRandomValues.CryptoRandom)
)

View File

@@ -1,21 +1,21 @@
import { Todo } from "@/domain" import { Todo } from "@/domain"
import { Box, Button, Card, Flex, TextArea } from "@radix-ui/themes" import { Box, Button, Card, Flex, TextArea } from "@radix-ui/themes"
import { GetRandomValues, makeUuid4 } from "@typed/id"
import { Effect, Option, Ref } from "effect" import { Effect, Option, Ref } from "effect"
import { R } from "../reffuse" import { R } from "../reffuse"
import { TodosState } from "../services" import { TodosState } from "../services"
const createEmptyTodo = Effect.map(Todo.generateUniqueID, id => Todo.Todo.make({ const createEmptyTodo = makeUuid4.pipe(
id, Effect.map(id => Todo.Todo.make({ id, content: "", completedAt: Option.none()}, true)),
content: "", Effect.provide(GetRandomValues.CryptoRandom),
completedAt: Option.none(), )
}, true))
export function VNewTodo() { export function VNewTodo() {
const todoRef = R.useRef(() => createEmptyTodo) const todoRef = R.useRef(() => createEmptyTodo)
const [content, setContent] = R.useRefState(R.useSubRef(todoRef, ["content"])) const [content, setContent] = R.useRefState(R.useSubRefFromPath(todoRef, ["content"]))
const add = R.useCallbackSync(() => Effect.all([TodosState.TodosState, todoRef]).pipe( const add = R.useCallbackSync(() => Effect.all([TodosState.TodosState, todoRef]).pipe(
Effect.flatMap(([state, todo]) => state.prepend(todo)), Effect.flatMap(([state, todo]) => state.prepend(todo)),

View File

@@ -1,20 +1,20 @@
import { Todo } from "@/domain" import { Todo } from "@/domain"
import { Box, Card, Flex, IconButton, TextArea } from "@radix-ui/themes" import { Box, Card, Flex, IconButton, TextArea } from "@radix-ui/themes"
import { Effect } from "effect" import { Effect, Ref, SubscriptionRef } from "effect"
import { Delete } from "lucide-react" import { Delete } from "lucide-react"
import { useState } from "react" import { useState } from "react"
import { R } from "../reffuse" import { R } from "../reffuse"
import { TodosState } from "../services"
export interface VTodoProps { export interface VTodoProps {
readonly index: number readonly todoRef: SubscriptionRef.SubscriptionRef<Todo.Todo>
readonly todo: Todo.Todo readonly remove: Effect.Effect<void>
} }
export function VTodo({ index, todo }: VTodoProps) { export function VTodo({ todoRef, remove }: VTodoProps) {
const runSync = R.useRunSync() const runSync = R.useRunSync()
const [todo] = R.useSubscribeRefs(todoRef)
const editorMode = useState(false) const editorMode = useState(false)
@@ -24,12 +24,11 @@ export function VTodo({ index, todo }: VTodoProps) {
<Flex direction="column" align="stretch" gap="1"> <Flex direction="column" align="stretch" gap="1">
<TextArea <TextArea
value={todo.content} value={todo.content}
onChange={e => TodosState.TodosState.pipe( onChange={e => runSync(
Effect.flatMap(state => state.replace( Ref.set(todoRef, Todo.Todo.make({
index, ...todo,
Todo.Todo.make({ ...todo, content: e.target.value }, true), content: e.target.value,
)), }, true))
runSync,
)} )}
disabled={!editorMode} disabled={!editorMode}
/> />
@@ -38,12 +37,7 @@ export function VTodo({ index, todo }: VTodoProps) {
<Box></Box> <Box></Box>
<Flex direction="row" align="center" gap="1"> <Flex direction="row" align="center" gap="1">
<IconButton <IconButton onClick={() => runSync(remove)}>
onClick={() => TodosState.TodosState.pipe(
Effect.flatMap(state => state.remove(index)),
runSync,
)}
>
<Delete /> <Delete />
</IconButton> </IconButton>
</Flex> </Flex>

View File

@@ -1,5 +1,5 @@
import { Box, Flex } from "@radix-ui/themes" import { Box, Flex } from "@radix-ui/themes"
import { Chunk, Effect } from "effect" import { Chunk, Effect, Ref } from "effect"
import { R } from "../reffuse" import { R } from "../reffuse"
import { TodosState } from "../services" import { TodosState } from "../services"
import { VNewTodo } from "./VNewTodo" import { VNewTodo } from "./VNewTodo"
@@ -8,7 +8,7 @@ import { VTodo } from "./VTodo"
export function VTodos() { export function VTodos() {
const todosRef = R.useMemo(() => TodosState.TodosState.pipe(Effect.map(state => state.todos)), []) const todosRef = R.useMemo(() => Effect.map(TodosState.TodosState, state => state.todos), [])
const [todos] = R.useSubscribeRefs(todosRef) const [todos] = R.useSubscribeRefs(todosRef)
@@ -20,7 +20,16 @@ export function VTodos() {
{Chunk.map(todos, (todo, index) => ( {Chunk.map(todos, (todo, index) => (
<Box key={todo.id} width="500px"> <Box key={todo.id} width="500px">
<VTodo index={index} todo={todo} /> <R.SubRefFromGetSet
parent={todosRef}
getter={parentValue => Chunk.unsafeGet(parentValue, index)}
setter={(parentValue, value) => Chunk.replace(parentValue, index, value)}
>
{ref => <VTodo
todoRef={ref}
remove={Ref.update(todosRef, Chunk.remove(index))}
/>}
</R.SubRefFromGetSet>
</Box> </Box>
))} ))}
</Flex> </Flex>